Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
D
dlib
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
钟尚武
dlib
Commits
88778d2c
Commit
88778d2c
authored
Feb 15, 2017
by
Davis King
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added find_gap_between_convex_hulls()
parent
7747be83
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
251 additions
and
0 deletions
+251
-0
optimization_solve_qp_using_smo.h
dlib/optimization/optimization_solve_qp_using_smo.h
+56
-0
optimization_solve_qp_using_smo_abstract.h
dlib/optimization/optimization_solve_qp_using_smo_abstract.h
+41
-0
opt_qp_solver.cpp
dlib/test/opt_qp_solver.cpp
+154
-0
No files found.
dlib/optimization/optimization_solve_qp_using_smo.h
View file @
88778d2c
...
...
@@ -551,6 +551,62 @@ namespace dlib
return
iter
+
1
;
}
// ----------------------------------------------------------------------------------------
template
<
typename
EXP1
,
typename
EXP2
,
typename
T
,
long
NRa
,
long
NRb
>
unsigned
long
find_gap_between_convex_hulls
(
const
matrix_exp
<
EXP1
>&
A
,
const
matrix_exp
<
EXP2
>&
B
,
matrix
<
T
,
NRa
,
1
>&
cA
,
matrix
<
T
,
NRb
,
1
>&
cB
,
const
double
eps
,
const
unsigned
long
max_iter
=
1000
)
{
DLIB_CASSERT
(
A
.
size
()
!=
0
);
DLIB_CASSERT
(
B
.
size
()
!=
0
);
DLIB_CASSERT
(
A
.
nr
()
==
B
.
nr
(),
"The dimensionality of the points in both convex hull sets must match"
);
DLIB_CASSERT
(
eps
>
0
);
DLIB_CASSERT
(
max_iter
>
0
);
cA
.
set_size
(
A
.
nc
());
cB
.
set_size
(
B
.
nc
());
// initialize to the centroids of A and B respectively.
cA
=
1
.
0
/
cA
.
size
();
cB
=
1
.
0
/
cB
.
size
();
matrix
<
T
>
AA
,
BB
,
AB
,
ABb
,
ABa
;
AA
=
trans
(
A
)
*
A
;
BB
=
trans
(
B
)
*
B
;
AB
=
trans
(
A
)
*
B
;
unsigned
long
iter
=
0
;
for
(
iter
=
0
;
iter
<
max_iter
;
++
iter
)
{
// find the convex combination of A that is nearest to B*cB
ABb
=
AB
*
cB
;
const
auto
smo_iter1
=
solve_qp_using_smo
(
AA
,
ABb
,
cA
,
eps
,
cA
.
size
());
// now find the convex combination of B that is nearest to A*cA
ABa
=
trans
(
AB
)
*
cA
;
const
auto
smo_iter2
=
solve_qp_using_smo
(
BB
,
ABa
,
cB
,
eps
,
cB
.
size
());
// stop if the QP solvers failed to improve
if
(
smo_iter1
==
1
&&
smo_iter2
==
1
)
break
;
}
return
iter
+
1
;
}
// ----------------------------------------------------------------------------------------
}
...
...
dlib/optimization/optimization_solve_qp_using_smo_abstract.h
View file @
88778d2c
...
...
@@ -162,6 +162,47 @@ namespace dlib
converge to eps accuracy then the number returned will be max_iter+1.
!*/
// ----------------------------------------------------------------------------------------
template
<
typename
EXP1
,
typename
EXP2
,
typename
T
,
long
NRa
,
long
NRb
>
unsigned
long
find_gap_between_convex_hulls
(
const
matrix_exp
<
EXP1
>&
A
,
const
matrix_exp
<
EXP2
>&
B
,
matrix
<
T
,
NRa
,
1
>&
cA
,
matrix
<
T
,
NRb
,
1
>&
cB
,
const
double
eps
,
const
unsigned
long
max_iter
=
1000
);
/*!
requires
- A.nr() == B.nr()
- A.size() != 0
- B.size() != 0
- eps > 0
- max_iter > 0
ensures
- If you think of A and B as sets of column vectors, then we can identify the
convex sets hullA and hullB, which are the convex hulls of A and B
respectively. This function finds the pair of points in hullA and hullB that
are nearest to each other. To be precise, this function solves the following
quadratic program:
Minimize: f(cA,cB) == length_squared(A*cA - B*cB)
subject to the following constraints on cA and cB:
- is_col_vector(cA) == true && cA.size() == A.nc()
- is_col_vector(cB) == true && cB.size() == B.nc()
- sum(cA) == 1 && min(cA) >= 0
- sum(cB) == 1 && min(cB) >= 0
- This function uses an iterative block coordinate descent algorithm to solve
the QP. It runs until either max_iter iterations have been performed or the
QP is solved to at least eps accuracy.
- returns the number of iterations performed. If this method fails to
converge to eps accuracy then the number returned will be max_iter+1.
!*/
// ----------------------------------------------------------------------------------------
}
...
...
dlib/test/opt_qp_solver.cpp
View file @
88778d2c
...
...
@@ -356,6 +356,157 @@ namespace
test_qp4_test7
();
}
// ----------------------------------------------------------------------------------------
double
max_distance_to
(
const
std
::
vector
<
matrix
<
double
,
0
,
1
>>&
a
,
const
std
::
vector
<
matrix
<
double
,
0
,
1
>>&
b
)
{
double
best_dist
=
0
;
for
(
auto
&&
aa
:
a
)
{
for
(
auto
&&
bb
:
b
)
{
double
dist
=
length
(
aa
-
bb
);
if
(
dist
>
best_dist
)
best_dist
=
dist
;
}
}
return
best_dist
;
}
double
min_distance_to
(
const
std
::
vector
<
matrix
<
double
,
0
,
1
>>&
a
,
const
std
::
vector
<
matrix
<
double
,
0
,
1
>>&
b
)
{
double
best_dist
=
std
::
numeric_limits
<
double
>::
infinity
();
for
(
auto
&&
aa
:
a
)
{
for
(
auto
&&
bb
:
b
)
{
double
dist
=
length
(
aa
-
bb
);
if
(
dist
<
best_dist
)
best_dist
=
dist
;
}
}
return
best_dist
;
}
double
min_distance_to
(
const
std
::
vector
<
matrix
<
double
,
0
,
1
>>&
s
,
const
matrix
<
double
,
0
,
1
>&
v
)
{
double
best_dist
=
std
::
numeric_limits
<
double
>::
infinity
();
for
(
auto
&
x
:
s
)
{
double
dist
=
length
(
v
-
x
);
if
(
dist
<
best_dist
)
{
best_dist
=
dist
;
}
}
return
best_dist
;
}
double
max_distance_to
(
const
std
::
vector
<
matrix
<
double
,
0
,
1
>>&
s
,
const
matrix
<
double
,
0
,
1
>&
v
)
{
double
best_dist
=
0
;
for
(
auto
&
x
:
s
)
{
double
dist
=
length
(
v
-
x
);
if
(
dist
>
best_dist
)
{
best_dist
=
dist
;
}
}
return
best_dist
;
}
void
test_find_gap_between_convex_hulls
()
{
print_spinner
();
std
::
vector
<
matrix
<
double
,
0
,
1
>>
set1
,
set2
;
const
double
dist_thresh
=
5.47723
;
// generate two groups of points that are pairwise close within each set and
// pairwise far apart between each set, according to dist_thresh distance threshold.
bool
which
=
true
;
for
(
size_t
i
=
0
;
i
<
10000
;
++
i
)
{
matrix
<
double
,
0
,
1
>
v
=
gaussian_randm
(
15
,
2
,
i
);
const
auto
min_dist1
=
min_distance_to
(
set1
,
v
);
const
auto
min_dist2
=
min_distance_to
(
set2
,
v
);
const
auto
max_dist1
=
max_distance_to
(
set1
,
v
);
const
auto
max_dist2
=
max_distance_to
(
set2
,
v
);
if
(
which
)
{
if
((
set1
.
size
()
==
0
||
max_dist1
<
dist_thresh
)
&&
min_dist2
>
dist_thresh
)
{
set1
.
push_back
(
v
);
which
=
!
which
;
}
}
else
{
if
((
set2
.
size
()
==
0
||
max_dist2
<
dist_thresh
)
&&
min_dist1
>
dist_thresh
)
{
set2
.
push_back
(
v
);
which
=
!
which
;
}
}
}
dlog
<<
LINFO
<<
"set1.size(): "
<<
set1
.
size
();
dlog
<<
LINFO
<<
"set2.size(): "
<<
set2
.
size
();
// make sure we generated the points correctly.
dlog
<<
LINFO
<<
"dist_thresh: "
<<
dist_thresh
;
dlog
<<
LINFO
<<
"max distance between set1 and set1: "
<<
max_distance_to
(
set1
,
set1
);
dlog
<<
LINFO
<<
"max distance between set2 and set2: "
<<
max_distance_to
(
set2
,
set2
);
DLIB_TEST
(
max_distance_to
(
set1
,
set1
)
<
dist_thresh
);
DLIB_TEST
(
max_distance_to
(
set2
,
set2
)
<
dist_thresh
);
dlog
<<
LINFO
<<
"min distance between set2 and set1: "
<<
min_distance_to
(
set2
,
set1
);
DLIB_TEST
(
min_distance_to
(
set2
,
set1
)
>
dist_thresh
);
// It is slightly counterintuitive but true that points picked using the above procedure
// will have elements of their convex hulls that are much closer together than
// dist_thresh, even though none of the vertices of the hulls are that close
// together. This is especially true in high dimensions. So let's use this to
// test find_gap_between_convex_hulls(). It should be able to find a pair of
// points in the convex hulls of our sets that are a lot closer together than
// dist_thresh.
// First we need to convert the vectors to matrices.
matrix
<
double
>
A
,
B
;
A
.
set_size
(
set1
[
0
].
size
(),
set1
.
size
());
B
.
set_size
(
set2
[
0
].
size
(),
set2
.
size
());
for
(
long
c
=
0
;
c
<
A
.
nc
();
++
c
)
set_colm
(
A
,
c
)
=
set1
[
c
];
for
(
long
c
=
0
;
c
<
B
.
nc
();
++
c
)
set_colm
(
B
,
c
)
=
set2
[
c
];
matrix
<
double
,
0
,
1
>
c1
,
c2
;
find_gap_between_convex_hulls
(
A
,
B
,
c1
,
c2
,
0.0001
);
// make sure c1 and c2 are convex combinations.
DLIB_TEST
(
abs
(
sum
(
c1
)
-
1
)
<
1e-8
);
DLIB_TEST
(
abs
(
sum
(
c2
)
-
1
)
<
1e-8
);
DLIB_TEST
(
min
(
c1
)
>=
0
);
DLIB_TEST
(
min
(
c2
)
>=
0
);
// now test that the points found are close together.
dlog
<<
LINFO
<<
"dist: "
<<
length
(
A
*
c1
-
B
*
c2
);
DLIB_TEST
(
length
(
A
*
c1
-
B
*
c2
)
<
4
);
}
// ----------------------------------------------------------------------------------------
class
opt_qp_solver_tester
:
public
tester
...
...
@@ -412,6 +563,9 @@ namespace
dlog
<<
LINFO
<<
"disagreement stddev: "
<<
rs
.
stddev
();
DLIB_TEST_MSG
(
rs
.
mean
()
<
0.001
,
rs
.
mean
());
DLIB_TEST_MSG
(
rs
.
stddev
()
<
0.001
,
rs
.
stddev
());
test_find_gap_between_convex_hulls
();
}
double
do_the_test
(
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment