Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
alta
alta
Commits
fc6add90
Commit
fc6add90
authored
Apr 08, 2013
by
Laurent Belcour
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixing the quadratic program to support streaming of constraints. It works now
but the streaming algorithm is dumb.
parent
bdf57e7e
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
298 additions
and
248 deletions
+298
-248
sources/plugins/rational_fitter_parallel/quadratic_program.h
sources/plugins/rational_fitter_parallel/quadratic_program.h
+224
-186
sources/plugins/rational_fitter_parallel/rational_fitter.cpp
sources/plugins/rational_fitter_parallel/rational_fitter.cpp
+74
-62
No files found.
sources/plugins/rational_fitter_parallel/quadratic_program.h
View file @
fc6add90
...
...
@@ -9,195 +9,233 @@
class
quadratic_program
{
public:
//! \brief Constructor need to specify the number of coefficients
quadratic_program
(
int
np
,
int
nq
)
:
_np
(
np
),
_nq
(
nq
),
CI
(
0.0
,
_np
+
_nq
,
0
)
{
}
//! \brief Remove the already defined constraints
void
clear_constraints
()
{
CI
.
resize
(
_np
+
_nq
,
0
);
}
//! \brief Add a constraint by specifying the vector
void
add_constraints
(
const
vec
&
c
)
{
const
int
m
=
CI
.
nrows
();
const
int
n
=
CI
.
ncols
();
if
(
n
>
0
)
{
// Construct temp buffer
double
*
temp
=
new
double
[
n
*
m
];
for
(
int
u
=
0
;
u
<
n
;
++
u
)
{
for
(
int
v
=
0
;
v
<
m
;
++
v
)
{
temp
[
u
*
m
+
v
]
=
CI
[
v
][
u
];
}
}
// Resize matrix CI
CI
.
resize
(
m
,
n
+
1
);
// Recopy data
for
(
int
u
=
0
;
u
<
n
+
1
;
++
u
)
{
if
(
u
==
n
)
{
for
(
int
v
=
0
;
v
<
m
;
++
v
)
CI
[
v
][
u
]
=
c
[
v
];
}
else
{
for
(
int
v
=
0
;
v
<
m
;
++
v
)
CI
[
v
][
u
]
=
temp
[
u
*
m
+
v
];
}
}
delete
[]
temp
;
}
else
{
// Resize matrix CI
CI
.
resize
(
m
,
1
);
// Recopy data
for
(
int
u
=
0
;
u
<
m
;
++
u
)
CI
[
n
][
u
]
=
c
[
u
];
}
}
//! \brief Provide the number of constraints
int
nb_constraints
()
const
{
return
CI
.
ncols
();
}
//! \brief Solves the quadratic program and update the p and
//! q vector if necessary.
inline
bool
solve_program
(
QuadProgPP
::
Vector
<
double
>&
x
,
double
&
delta
,
vec
&
p
,
vec
&
q
)
{
bool
solves_qp
=
solve_program
(
x
,
delta
)
;
if
(
solves_qp
)
{
double
norm
=
0.0
;
for
(
int
i
=
0
;
i
<
_np
+
_nq
;
++
i
)
{
const
double
v
=
x
[
i
];
norm
+=
v
*
v
;
if
(
i
<
_np
)
{
p
[
i
]
=
v
;
}
else
{
q
[
i
-
_np
]
=
v
;
}
}
return
norm
>
0.0
;
}
else
{
return
false
;
}
}
//! \brief Solves the quadratic program
inline
bool
solve_program
(
QuadProgPP
::
Vector
<
double
>&
v
,
double
&
delta
)
{
const
int
m
=
CI
.
nrows
();
const
int
n
=
CI
.
ncols
();
QuadProgPP
::
Matrix
<
double
>
G
(
0.0
,
m
,
m
)
;
QuadProgPP
::
Vector
<
double
>
g
(
0.0
,
m
)
;
QuadProgPP
::
Vector
<
double
>
ci
(
0.0
,
n
)
;
QuadProgPP
::
Matrix
<
double
>
CE
(
0.0
,
m
,
0
)
;
QuadProgPP
::
Vector
<
double
>
ce
(
0.0
,
0
)
;
// Update the ci column with the delta parameter
// (See Celis et al. 2007 p.12)
Eigen
::
JacobiSVD
<
Eigen
::
MatrixXd
,
Eigen
::
HouseholderQRPreconditioner
>
svd
(
Eigen
::
MatrixXd
::
Map
(
&
CI
[
0
][
0
],
m
,
n
));
const
double
sigma_m
=
svd
.
singularValues
()(
std
::
min
(
m
,
n
)
-
1
)
;
const
double
sigma_M
=
svd
.
singularValues
()(
0
)
;
delta
=
sigma_M
/
sigma_m
;
// Select the size of the result vector to
// be equal to the dimension of p + q
for
(
int
i
=
0
;
i
<
m
;
++
i
)
{
G
[
i
][
i
]
=
1.0
;
}
// Each constraint (fitting interval or point
// add another dimension to the constraint
// matrix
for
(
int
i
=
0
;
i
<
n
;
++
i
)
{
// Norm of the row vector
double
norm
=
0.0
;
for
(
int
j
=
0
;
j
<
m
;
++
j
)
{
norm
+=
CI
[
j
][
i
]
*
CI
[
j
][
i
]
;
;
}
// Set the c vector, will later be updated using the
// delta parameter.
ci
[
i
]
=
-
delta
*
sqrt
(
norm
)
;
}
// Compute the solution
const
double
cost
=
QuadProgPP
::
solve_quadprog
(
G
,
g
,
CE
,
ce
,
CI
,
ci
,
v
);
bool
solves_qp
=
!
(
cost
==
std
::
numeric_limits
<
double
>::
infinity
());
return
solves_qp
;
}
//! \brief Test all the constraints of the data
bool
test_constraints
(
const
rational_function
*
r
,
const
vertical_segment
*
data
)
{
int
nb_failed
=
0
;
for
(
int
n
=
0
;
n
<
data
->
size
();
++
n
)
{
vec
x
,
yl
,
yu
;
data
->
get
(
n
,
x
,
yl
,
yu
);
vec
y
=
r
->
value
(
x
);
if
(
y
<
yl
||
y
>
yu
)
{
nb_failed
++
;
}
}
public:
//! \brief Constructor need to specify the number of coefficients
quadratic_program
(
int
np
,
int
nq
)
:
_np
(
np
),
_nq
(
nq
),
CI
(
0.0
,
_np
+
_nq
,
0
)
{
}
//! \brief Remove the already defined constraints
void
clear_constraints
()
{
CI
.
resize
(
_np
+
_nq
,
0
);
}
//! \brief Add a constraint by specifying the vector
void
add_constraints
(
const
vec
&
c
)
{
const
int
m
=
CI
.
nrows
();
const
int
n
=
CI
.
ncols
();
if
(
n
>
0
)
{
// Construct temp buffer
double
*
temp
=
new
double
[
n
*
m
];
for
(
int
u
=
0
;
u
<
n
;
++
u
)
{
for
(
int
v
=
0
;
v
<
m
;
++
v
)
{
temp
[
u
*
m
+
v
]
=
CI
[
v
][
u
];
}
}
// Resize matrix CI
CI
.
resize
(
m
,
n
+
1
);
// Recopy data
for
(
int
u
=
0
;
u
<
n
+
1
;
++
u
)
{
if
(
u
==
n
)
{
for
(
int
v
=
0
;
v
<
m
;
++
v
)
CI
[
v
][
u
]
=
c
[
v
];
}
else
{
for
(
int
v
=
0
;
v
<
m
;
++
v
)
CI
[
v
][
u
]
=
temp
[
u
*
m
+
v
];
}
}
delete
[]
temp
;
}
else
{
// Resize matrix CI
CI
.
resize
(
m
,
1
);
// Recopy data
for
(
int
u
=
0
;
u
<
m
;
++
u
)
CI
[
n
][
u
]
=
c
[
u
];
}
}
//! \brief Provide the number of constraints
int
nb_constraints
()
const
{
return
CI
.
ncols
();
}
//! \brief Solves the quadratic program and update the p and
//! q vector if necessary.
inline
bool
solve_program
(
QuadProgPP
::
Vector
<
double
>&
x
,
double
&
delta
,
vec
&
p
,
vec
&
q
)
{
bool
solves_qp
=
solve_program
(
x
,
delta
)
;
if
(
solves_qp
)
{
double
norm
=
0.0
;
for
(
int
i
=
0
;
i
<
_np
+
_nq
;
++
i
)
{
const
double
v
=
x
[
i
];
norm
+=
v
*
v
;
if
(
i
<
_np
)
{
p
[
i
]
=
v
;
}
else
{
q
[
i
-
_np
]
=
v
;
}
}
return
norm
>
0.0
;
}
else
{
return
false
;
}
}
//! \brief Solves the quadratic program
inline
bool
solve_program
(
QuadProgPP
::
Vector
<
double
>&
v
,
double
&
delta
)
{
const
int
m
=
CI
.
nrows
();
const
int
n
=
CI
.
ncols
();
QuadProgPP
::
Matrix
<
double
>
G
(
0.0
,
m
,
m
)
;
QuadProgPP
::
Vector
<
double
>
g
(
0.0
,
m
)
;
QuadProgPP
::
Vector
<
double
>
ci
(
0.0
,
n
)
;
QuadProgPP
::
Matrix
<
double
>
CE
(
0.0
,
m
,
0
)
;
QuadProgPP
::
Vector
<
double
>
ce
(
0.0
,
0
)
;
// Update the ci column with the delta parameter
// (See Celis et al. 2007 p.12)
Eigen
::
JacobiSVD
<
Eigen
::
MatrixXd
,
Eigen
::
HouseholderQRPreconditioner
>
svd
(
Eigen
::
MatrixXd
::
Map
(
&
CI
[
0
][
0
],
m
,
n
));
const
double
sigma_m
=
svd
.
singularValues
()(
std
::
min
(
m
,
n
)
-
1
)
;
const
double
sigma_M
=
svd
.
singularValues
()(
0
)
;
delta
=
sigma_M
/
sigma_m
;
// Select the size of the result vector to
// be equal to the dimension of p + q
for
(
int
i
=
0
;
i
<
m
;
++
i
)
{
G
[
i
][
i
]
=
1.0
;
}
// Each constraint (fitting interval or point
// add another dimension to the constraint
// matrix
for
(
int
i
=
0
;
i
<
n
;
++
i
)
{
// Norm of the row vector
double
norm
=
0.0
;
for
(
int
j
=
0
;
j
<
m
;
++
j
)
{
norm
+=
CI
[
j
][
i
]
*
CI
[
j
][
i
]
;
;
}
// Set the c vector, will later be updated using the
// delta parameter.
ci
[
i
]
=
-
delta
*
sqrt
(
norm
)
;
}
// Compute the solution
const
double
cost
=
QuadProgPP
::
solve_quadprog
(
G
,
g
,
CE
,
ce
,
CI
,
ci
,
v
);
bool
solves_qp
=
!
(
cost
==
std
::
numeric_limits
<
double
>::
infinity
());
return
solves_qp
;
}
//! \brief Test all the constraints of the data
bool
test_constraints
(
int
ny
,
const
rational_function
*
r
,
const
vertical_segment
*
data
)
{
int
nb_failed
=
0
;
for
(
int
n
=
0
;
n
<
data
->
size
();
++
n
)
{
vec
x
,
yl
,
yu
;
data
->
get
(
n
,
x
,
yl
,
yu
);
vec
y
=
r
->
value
(
x
);
bool
fail_upper
=
y
>
yu
;
bool
fail_lower
=
y
<
yl
;
if
(
fail_lower
||
fail_upper
)
{
nb_failed
++
;
vec
cu
,
cl
;
get_constraint
(
x
,
yl
,
yu
,
ny
,
r
,
cu
,
cl
);
add_constraints
(
cu
);
add_constraints
(
cl
);
}
}
#ifdef DEBUG
std
::
cout
<<
"<<TRACE>> "
<<
nb_failed
<<
" constraints where not satified."
<<
std
::
endl
;
std
::
cout
<<
"<<TRACE>> "
<<
nb_failed
<<
" constraints where not satified."
<<
std
::
endl
;
#endif
return
nb_failed
==
0
;
}
//! \brief Give the next position in the data that is not satisfied.
//! This method works only for a single color channel ny !
static
int
next_unmatching_constraint
(
int
i
,
int
ny
,
const
rational_function
*
r
,
const
vertical_segment
*
data
)
{
for
(
int
n
=
i
;
n
<
data
->
size
();
++
n
)
{
vec
x
,
yl
,
yu
;
data
->
get
(
n
,
x
,
yl
,
yu
);
vec
y
=
r
->
value
(
x
);
if
(
y
[
ny
]
<
yl
[
ny
]
||
y
[
ny
]
>
yu
[
ny
])
{
return
nb_failed
==
0
;
}
//! \brief Generate two constraint vectors from a vertical segment and a
//! ration function type.
inline
void
get_constraint
(
const
vec
&
xi
,
const
vec
&
yl
,
const
vec
&
yu
,
int
ny
,
const
rational_function
*
func
,
vec
&
cu
,
vec
&
cl
)
{
cu
.
resize
(
_np
+
_nq
);
cl
.
resize
(
_np
+
_nq
);
// Create two vector of constraints
for
(
int
j
=
0
;
j
<
_np
+
_nq
;
++
j
)
{
// Filling the p part
if
(
j
<
_np
)
{
const
double
pi
=
func
->
p
(
xi
,
j
)
;
cu
[
j
]
=
pi
;
cl
[
j
]
=
-
pi
;
}
// Filling the q part
else
{
const
double
qi
=
func
->
q
(
xi
,
j
-
_np
)
;
cu
[
j
]
=
-
yu
[
ny
]
*
qi
;
cl
[
j
]
=
yl
[
ny
]
*
qi
;
}
}
}
//! \brief Give the next position in the data that is not satisfied.
//! This method works only for a single color channel ny !
static
int
next_unmatching_constraint
(
int
i
,
int
ny
,
const
rational_function
*
r
,
const
vertical_segment
*
data
)
{
for
(
int
n
=
i
;
n
<
data
->
size
();
++
n
)
{
vec
x
,
yl
,
yu
;
data
->
get
(
n
,
x
,
yl
,
yu
);
vec
y
=
r
->
value
(
x
);
if
(
y
[
ny
]
<
yl
[
ny
]
||
y
[
ny
]
>
yu
[
ny
])
{
return
n
;
}
}
return
data
->
size
();
}
protected:
int
_np
,
_nq
;
QuadProgPP
::
Matrix
<
double
>
CI
;
}
}
return
data
->
size
();
}
protected:
int
_np
,
_nq
;
QuadProgPP
::
Matrix
<
double
>
CI
;
};
sources/plugins/rational_fitter_parallel/rational_fitter.cpp
View file @
fc6add90
...
...
@@ -52,13 +52,14 @@ bool rational_fitter_parallel::fit_data(const data* dat, function* fit, const ar
r
->
setMin
(
d
->
min
())
;
r
->
setMax
(
d
->
max
())
;
const
int
_min_np
=
args
.
get_int
(
"min-np"
,
10
);
const
int
_max_np
=
args
.
get_int
(
"np"
,
_min_np
);
const
int
_min_np
=
args
.
get_int
(
"min-np"
,
10
);
const
int
_max_np
=
args
.
get_int
(
"np"
,
_min_np
);
std
::
cout
<<
"<<INFO>> N in ["
<<
_min_np
<<
", "
<<
_max_np
<<
"]"
<<
std
::
endl
;
for
(
int
i
=
_min_np
;
i
<=
_max_np
;
++
i
)
{
std
::
cout
<<
"<<INFO>> fit using np+nq = "
<<
i
<<
"
\r
"
;
std
::
cout
<<
"<<INFO>> fit using np+nq = "
<<
i
<<
std
::
endl
;
std
::
cout
.
flush
()
;
QTime
time
;
time
.
start
()
;
...
...
@@ -82,31 +83,32 @@ bool rational_fitter_parallel::fit_data(const data* dat, function* fit, const ar
#ifdef DEBUG
std
::
cout
<<
"<<DEBUG>> will use "
<<
nb_cores
<<
" threads to compute the quadratic programs"
<<
std
::
endl
;
#endif
omp_set_num_threads
(
nb_cores
)
;
std
::
vector
<
rational_function
*>
rs
;
for
(
int
j
=
0
;
j
<
nb_cores
;
++
j
)
{
rational_function
*
rj
=
dynamic_cast
<
rational_function
*>
(
plugins_manager
::
get_function
(
args
[
"func"
]));
std
::
vector
<
rational_function
*>
rs
;
for
(
int
j
=
0
;
j
<
nb_cores
;
++
j
)
{
rational_function
*
rj
=
dynamic_cast
<
rational_function
*>
(
plugins_manager
::
get_function
(
args
[
"func"
]));
rj
->
setDimX
(
d
->
dimX
())
;
rj
->
setDimY
(
d
->
dimY
()
)
;
rj
->
setMin
(
d
->
min
())
;
rj
->
setMax
(
d
->
max
())
;
rj
->
setDimX
(
d
->
dimX
())
;
rj
->
setDimY
(
1
)
;
rj
->
setMin
(
d
->
min
())
;
rj
->
setMax
(
d
->
max
())
;
if
(
rj
==
NULL
)
{
std
::
cerr
<<
"<<ERROR>> unable to obtain a rational function from the plugins manager"
<<
std
::
endl
;
return
false
;
}
rs
.
push_back
(
rj
);
}
if
(
rj
==
NULL
)
{
std
::
cerr
<<
"<<ERROR>> unable to obtain a rational function from the plugins manager"
<<
std
::
endl
;
return
false
;
}
rs
.
push_back
(
rj
);
}
double
min_delta
=
std
::
numeric_limits
<
double
>::
max
();
int
nb_sol_found
=
0
;
int
np
,
nq
;
#pragma omp parallel for
//
#pragma omp parallel for
for
(
int
j
=
1
;
j
<
i
;
++
j
)
{
int
temp_np
=
i
-
j
;
...
...
@@ -115,10 +117,10 @@ bool rational_fitter_parallel::fit_data(const data* dat, function* fit, const ar
vec
p
(
temp_np
*
r
->
dimY
()),
q
(
temp_nq
*
r
->
dimY
());
double
delta
;
bool
is_fitted
=
fit_data
(
d
,
temp_np
,
temp_nq
,
rs
[
omp_get_thread_num
()],
p
,
q
,
delta
);
bool
is_fitted
=
fit_data
(
d
,
temp_np
,
temp_nq
,
rs
[
omp_get_thread_num
()],
p
,
q
,
delta
);
if
(
is_fitted
)
{
#pragma omp critical
#pragma omp critical
{
++
nb_sol_found
;
if
(
delta
<
min_delta
)
...
...
@@ -136,11 +138,11 @@ bool rational_fitter_parallel::fit_data(const data* dat, function* fit, const ar
}
}
// Clean memory
for
(
int
j
=
0
;
j
<
nb_cores
;
++
j
)
{
delete
rs
[
j
];
}
// Clean memory
for
(
int
j
=
0
;
j
<
nb_cores
;
++
j
)
{
delete
rs
[
j
];
}
if
(
min_delta
<
std
::
numeric_limits
<
double
>::
max
())
{
...
...
@@ -165,8 +167,8 @@ void rational_fitter_parallel::set_parameters(const arguments& args)
bool
rational_fitter_parallel
::
fit_data
(
const
vertical_segment
*
d
,
int
np
,
int
nq
,
rational_function
*
r
,
vec
&
P
,
vec
&
Q
,
double
&
delta
)
rational_function
*
r
,
vec
&
P
,
vec
&
Q
,
double
&
delta
)
{
for
(
int
j
=
0
;
j
<
d
->
dimY
();
++
j
)
{
...
...
@@ -186,71 +188,81 @@ bool rational_fitter_parallel::fit_data(const vertical_segment* d, int np, int n
// y is the dimension to fit on the y-data (e.g. R, G or B for RGB signals)
// the function return a ration BRDF function and a boolean
bool
rational_fitter_parallel
::
fit_data
(
const
vertical_segment
*
d
,
int
np
,
int
nq
,
int
ny
,
rational_function
*
r
,
vec
&
p
,
vec
&
q
,
double
&
delta
)
rational_function
*
r
,
vec
&
p
,
vec
&
q
,
double
&
delta
)
{
const
int
m
=
d
->
size
();
// 2*m = number of constraints
const
int
n
=
np
+
nq
;
// n = np+nq
const
int
n
=
np
+
nq
;
// n = np+nq
quadratic_program
qp
(
np
,
nq
);
quadratic_program
qp
(
np
,
nq
);
#ifndef TODO_PUT_IN_METHOD
for
(
int
i
=
0
;
i
<
d
->
size
()
/
10
;
++
i
)
for
(
int
i
=
0
;
i
<
d
->
size
()
/
10
0
;
++
i
)
{
// Create two vector of constraints
vec
c1
(
n
),
c2
(
n
);
get_constraint
(
10
*
i
,
np
,
nq
,
ny
,
d
,
r
,
c1
,
c2
);
get_constraint
(
10
0
*
i
,
np
,
nq
,
ny
,
d
,
r
,
c1
,
c2
);
qp
.
add_constraints
(
c1
);
qp
.
add_constraints
(
c2
);
}
#endif
while
(
true
)
while
(
qp
.
nb_constraints
()
<
2
*
m
)
{
#ifdef DEBUG
std
::
cout
<<
"<<DEBUG>> number of constraints = "
<<
qp
.
nb_constraints
()
<<
std
::
endl
;
#endif
QuadProgPP
::
Vector
<
double
>
x
(
n
);
bool
solves_qp
=
qp
.
solve_program
(
x
,
delta
,
p
,
q
);
r
->
update
(
p
,
q
);
if
(
solves_qp
)
{
if
(
qp
.
test_constraints
(
ny
,
r
,
d
))
{
#ifdef DEBUG
std
::
cout
<<
"<<INFO>> got solution "
<<
*
r
<<
std
::
endl
;
std
::
cout
<<
"<<INFO>> got solution "
<<
*
r
<<
std
::
endl
;
#endif
/*
int current = 0, i=0;
while(i < 100 && current < m)
{
/*
int current = 0, i=0;
while(i < 100 && current < m)
{
int next = quadratic_program::next_unmatching_constraint(current, ny, );