Conversation
|
Regression test case:
Provided test case doesn't fail without the patch. |
|
@alalek thanks for comment. |
modules/core/src/lpsolver.cpp
Outdated
| bool all_nonzero=true; | ||
| for(pos_ptr=c.begin();pos_ptr!=c.end();pos_ptr++,pos_ctr++){ | ||
| if(*pos_ptr==0){ | ||
| if ((*pos_ptr >= -1e-12) && (*pos_ptr <= 1e-12)) |
There was a problem hiding this comment.
- avoid magic constants
- use fabs() to compare near 0
const double SOLVELP_EPS = 1e-12;
...
if (fabs(*pos_ptr) < SOLVELP_EPS)
modules/core/src/lpsolver.cpp
Outdated
| if(*pos_ptr==0){ | ||
| if ((*pos_ptr >= -1e-12) && (*pos_ptr <= 1e-12)) | ||
| *pos_ptr = 0.0; | ||
| if(*pos_ptr==0.0){ |
There was a problem hiding this comment.
The second check can be eliminated:
- if the first condition is true, then the second condition is true too.
- if the first condition is false, then the second condition is false too.
For finite / infinite and NaN values.
| double val=it[b.cols-1]/myite; | ||
| if(val<min || (val==min && B[row_it]<min_var)){ | ||
| if((val<min) || ((val==min) && (B[row_it]<min_var))){ |
There was a problem hiding this comment.
(not a part of this fix)
prefer multiplication over division.
(a/b < c) ==> (a < c*b) (works if b > 0)
(a/b == c) ==> (a == c*b)
modules/core/test/test_lpsolver.cpp
Outdated
| 4., 0., 4., 1., 4.); | ||
|
|
||
| Mat z; | ||
| int result = cv::solveLP(A,B,z); |
There was a problem hiding this comment.
I believe, we still need some normalization or auto-tuning of SOLVELP_EPS value.
cv::solveLP(A,B,z);=>OKcv::solveLP(A,B*2,z);=>OKcv::solveLP(A,B*10,z);=>OKcv::solveLP(A,B*1e3,z);=>OKcv::solveLP(A,B*1e4,z);=>FAIL
A can be multiplied by any positive scalar too.
BTW, use 2**k multiplier to minimize calculation errors in normalization (if normalization is going to be used).
| @@ -259,10 +268,12 @@ static int inner_simplex(Mat_<double>& c, Mat_<double>& b,double& v,vector<int>& | |||
| int e=-1,pos_ctr=0,min_var=INT_MAX; | |||
There was a problem hiding this comment.
Please remove buggy "static" modifier from variable too
modules/core/src/lpsolver.cpp
Outdated
| } | ||
| //check constraints feasibility | ||
| Mat prod = Constr(Rect(0, 0, Constr.cols - 1, Constr.rows)) * z; | ||
| Mat constr_check = (prod - 1e-12) > Constr.col(Constr.cols - 1); |
There was a problem hiding this comment.
Mat constr_check = Constr.col(Constr.cols - 1) - prod;
double minValue = 0;
minMaxIdx(constr_check, &minValue) // we need minValue only
Analyze `minValue`
| //! return codes for cv::solveLP() function | ||
| enum SolveLPResult | ||
| { | ||
| SOLVELP_LOST = -3, //!< problem is feasible, but solver lost solution due to floating-point numbers representation error |
There was a problem hiding this comment.
"due to floating-point arithmetic errors"
| for (int i = 1; i < 1e5; i*=5) | ||
| { | ||
| Mat z; | ||
| int result = cv::solveLP(A,B*i,z); |
There was a problem hiding this comment.
In linear task both A/B should be multiplied to keep the same result.
There was a problem hiding this comment.
No it's not true. 5x+10y < 25 is the same as x+2y < 5. So mathematically it's correct test, but the idea of test is not obvious. Is the provided matrix is bed defined for Simplex Method?
|
@rayonnant14 Friendly reminder. |
1 similar comment
|
@rayonnant14 Friendly reminder. |
|
@rayonnant14 Friednly reminder. |
1 similar comment
|
@rayonnant14 Friednly reminder. |
| double myite=0; | ||
| //check constraints, select the tightest one, reinforcing Bland's rule | ||
| if((myite=it[e])>0){ | ||
| if (fabs(it[b.cols-1]) <= SOLVELP_EPS_REL * fabs(it[b.cols-1]) + SOLVELP_EPS_ABS) |
There was a problem hiding this comment.
The check is equivalent to (1-SOLVELP_EPS_REL)*fabs(it[b.cols-1] <= SOLVELP_EPS_ABSorfabs(it[b.cols-1] < SOLVELP_EPS_ABS/0.2`. I do not think that it's expected.
fix #12343
Pull Request Readiness Checklist
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
Patch to opencv_extra has the same branch name.