00001
00035
00036
00037
00038 #include <SharkDefs.h>
00039 #include <Rng/GlobalRng.h>
00040 #include <Array/ArrayIo.h>
00041 #include <Array/ArrayOp.h>
00042 #include <LinAlg/LinAlg.h>
00043 #include <ReClaM/QuadraticProgram.h>
00044
00045 #include <math.h>
00046 #include <time.h>
00047 #include <iostream>
00048 #include <iomanip>
00049
00050
00051 using namespace std;
00052
00053
00054
00055 #define XCHG_A(t, a, i, j) {t temp; temp = a(i); a(i) = a(j); a(j) = temp;}
00056 #define XCHG_V(t, a, i, j) {t temp; temp = a[i]; a[i] = a[j]; a[j] = temp;}
00057
00058
00060
00061
00062 QPSolver::QPSolver()
00063 {
00064 }
00065
00066 QPSolver::~QPSolver()
00067 {
00068 }
00069
00070
00072
00073
00074 QPMatrix::QPMatrix(unsigned int size)
00075 {
00076 matrixsize = size;
00077 }
00078
00079 QPMatrix::~QPMatrix()
00080 {
00081 }
00082
00083
00085
00086
00087 KernelMatrix::KernelMatrix(KernelFunction* kernelfunction,
00088 const Array<double>& data)
00089 : QPMatrix(data.dim(0))
00090 , kernel(kernelfunction)
00091 {
00092 x.resize(matrixsize, false);
00093 unsigned int i;
00094 for (i = 0; i < matrixsize; i++)
00095 {
00096 x(i) = new ArrayReference<double>(data[i]);
00097 }
00098 }
00099
00100 KernelMatrix::~KernelMatrix()
00101 {
00102 unsigned int i;
00103 for (i = 0; i < matrixsize; i++)
00104 {
00105 delete x(i);
00106 }
00107 }
00108
00109
00110 float KernelMatrix::Entry(unsigned int i, unsigned int j)
00111 {
00112 return (float)kernel->eval(*x(i), *x(j));
00113 }
00114
00115 void KernelMatrix::FlipColumnsAndRows(unsigned int i, unsigned int j)
00116 {
00117 XCHG_A(ArrayReference<double>*, x, i, j);
00118 }
00119
00120
00122
00123
00124 RegularizedKernelMatrix::RegularizedKernelMatrix(KernelFunction* kernel,
00125 const Array<double>& data,
00126 const Array<double>& diagModification)
00127 : KernelMatrix(kernel, data)
00128 {
00129 SIZE_CHECK(data.dim(0) == diagModification.dim(0));
00130 diagMod = diagModification;
00131 }
00132
00133 RegularizedKernelMatrix::~RegularizedKernelMatrix()
00134 {
00135 }
00136
00137
00138 float RegularizedKernelMatrix::Entry(unsigned int i, unsigned int j)
00139 {
00140 float ret = (float)KernelMatrix::Entry(i, j);
00141 if (i == j) ret += (float)diagMod(i);
00142 return ret;
00143 }
00144
00145 void RegularizedKernelMatrix::FlipColumnsAndRows(unsigned int i, unsigned int j)
00146 {
00147 KernelMatrix::FlipColumnsAndRows(i, j);
00148
00149 XCHG_A(double, diagMod, i, j);
00150 }
00151
00152
00154
00155
00156 QPMatrix2::QPMatrix2(QPMatrix* base)
00157 : QPMatrix(2 * base->getMatrixSize())
00158 {
00159 baseMatrix = base;
00160
00161 mapping.resize(matrixsize, false);
00162
00163 unsigned int i, ic = base->getMatrixSize();
00164 for (i = 0; i < ic; i++)
00165 {
00166 mapping(i) = i;
00167 mapping(i + ic) = i;
00168 }
00169 }
00170
00171 QPMatrix2::~QPMatrix2()
00172 {
00173 delete baseMatrix;
00174 }
00175
00176
00177 float QPMatrix2::Entry(unsigned int i, unsigned int j)
00178 {
00179 return baseMatrix->Entry(mapping(i), mapping(j));
00180 }
00181
00182 void QPMatrix2::FlipColumnsAndRows(unsigned int i, unsigned int j)
00183 {
00184 XCHG_A(unsigned int, mapping, i, j);
00185 }
00186
00187
00189
00190
00191 InputLabelMatrix::InputLabelMatrix(KernelFunction* kernelfunction,
00192 const Array<double>& input,
00193 const Array<double>& target,
00194 const Array<double>& prototypes)
00195 : QPMatrix(input.dim(0))
00196 , kernel(kernelfunction)
00197 {
00198 unsigned int i, j, m, classes = prototypes.dim(0);
00199
00200 x.resize(matrixsize, false);
00201 y.resize(matrixsize);
00202 for (i=0; i < matrixsize; i++)
00203 {
00204 x(i) = new ArrayReference<double>(input[i]);
00205 y[i] = (unsigned int)target(i, 0);
00206 }
00207
00208 prototypeProduct.resize(classes, classes, false);
00209 for (i=0; i<classes; i++)
00210 {
00211 for (j=0; j<=i; j++)
00212 {
00213 double scp = 0.0;
00214 for (m=0; m<classes; m++) scp += prototypes(i, m) * prototypes(j, m);
00215 prototypeProduct(i, j) = prototypeProduct(j, i) = scp;
00216 }
00217 }
00218 }
00219
00220 InputLabelMatrix::~InputLabelMatrix()
00221 {
00222 unsigned int i;
00223 for (i = 0; i < matrixsize; i++) delete x(i);
00224 }
00225
00226
00227 float InputLabelMatrix::Entry(unsigned int i, unsigned int j)
00228 {
00229 return (float)(kernel->eval(*x(i), *x(j)) * prototypeProduct(y[i], y[j]));
00230 }
00231
00232 void InputLabelMatrix::FlipColumnsAndRows(unsigned int i, unsigned int j)
00233 {
00234 XCHG_A(ArrayReference<double>*, x, i, j);
00235 XCHG_V(unsigned int, y, i, j);
00236 }
00237
00238
00240
00241
00242 CachedMatrix::CachedMatrix(QPMatrix* base, unsigned int cachesize)
00243 : QPMatrix(base->getMatrixSize())
00244 {
00245 baseMatrix = base;
00246
00247 cacheSize = 0;
00248 cacheMaxSize = cachesize;
00249 cacheNewest = -1;
00250 cacheOldest = -1;
00251
00252 cacheEntry.resize(matrixsize);
00253 unsigned int i;
00254 for (i = 0; i < matrixsize; i++)
00255 {
00256 cacheEntry[i].data = NULL;
00257 cacheEntry[i].length = 0;
00258 cacheEntry[i].older = -2;
00259 cacheEntry[i].newer = -2;
00260 }
00261 if (cachesize < 2 * matrixsize) throw SHARKEXCEPTION("[CachedMatrix::CachedMatrix] invalid cache size");
00262
00263 }
00264
00265 CachedMatrix::~CachedMatrix()
00266 {
00267 cacheClear();
00268 }
00269
00270
00271 float* CachedMatrix::Row(unsigned int k, unsigned int begin, unsigned int end, bool temp)
00272 {
00273 if (temp)
00274 {
00275
00276 cacheTemp.resize(end);
00277 if (cacheEntry[k].length > (int)begin)
00278 {
00279 memcpy(&cacheTemp[0] + begin, cacheEntry[k].data + begin, sizeof(float) * (cacheEntry[k].length - begin));
00280 begin = cacheEntry[k].length;
00281 }
00282 unsigned int col;
00283 for (col = begin; col < end; col++) cacheTemp[col] = baseMatrix->Entry(k, col);
00284 return &cacheTemp[0];
00285 }
00286 else
00287 {
00288
00289 unsigned int l = cacheEntry[k].length;
00290 while (cacheSize + end > cacheMaxSize + l)
00291 {
00292 if (cacheOldest == (int)k)
00293 {
00294 cacheRemove(k);
00295 cacheAppend(k);
00296 }
00297 cacheDelete(cacheOldest);
00298 }
00299 if (l == 0)
00300 {
00301 cacheAdd(k, end);
00302 }
00303 else
00304 {
00305 cacheResize(k, end);
00306 if ((int)k != cacheNewest)
00307 {
00308 cacheRemove(k);
00309 cacheAppend(k);
00310 }
00311 }
00312
00313
00314 if (l < end)
00315 {
00316 float* p = cacheEntry[k].data + l;
00317 unsigned int col;
00318 for (col = l; col < end; col++)
00319 {
00320 *p = baseMatrix->Entry(k, col);
00321 p++;
00322 }
00323 }
00324
00325 return cacheEntry[k].data;
00326 }
00327 }
00328
00329 float CachedMatrix::Entry(unsigned int i, unsigned int j)
00330 {
00331 return baseMatrix->Entry(i, j);
00332 }
00333
00334 void CachedMatrix::FlipColumnsAndRows(unsigned int i, unsigned int j)
00335 {
00336 int t;
00337
00338 baseMatrix->FlipColumnsAndRows(i, j);
00339
00340
00341 t = cacheEntry[i].older;
00342 if (t != -2)
00343 {
00344 if (t == -1) cacheOldest = j;
00345 else cacheEntry[t].newer = j;
00346 t = cacheEntry[i].newer;
00347 if (t == -1) cacheNewest = j;
00348 else cacheEntry[t].older = j;
00349 }
00350 t = cacheEntry[j].older;
00351 if (cacheEntry[j].older != -2)
00352 {
00353 if (t == -1) cacheOldest = i;
00354 else cacheEntry[t].newer = i;
00355 t = cacheEntry[j].newer;
00356 if (t == -1) cacheNewest = i;
00357 else cacheEntry[t].older = i;
00358 }
00359
00360
00361 XCHG_V(tCacheEntry, cacheEntry, i, j);
00362
00363
00364 unsigned int k, l;
00365 for (k = 0; k < matrixsize; k++)
00366 {
00367 l = cacheEntry[k].length;
00368 if (j < l)
00369 {
00370 XCHG_V(float, cacheEntry[k].data, i, j);
00371 }
00372 else if (i < l)
00373 {
00374
00375 cacheEntry[k].data[i] = baseMatrix->Entry(k, i);
00376 }
00377 }
00378 }
00379
00380 void CachedMatrix::CacheRowResize(unsigned int k, unsigned int newsize)
00381 {
00382 if (cacheEntry[k].data == NULL) cacheAdd(k, newsize);
00383 else cacheResize(k, newsize);
00384 }
00385
00386 void CachedMatrix::CacheRowRelease(unsigned int k)
00387 {
00388 if (cacheEntry[k].data != NULL) cacheDelete(k);
00389 }
00390
00391 void CachedMatrix::cacheAppend(int var)
00392 {
00393 if (cacheNewest == -1)
00394 {
00395 cacheNewest = var;
00396 cacheOldest = var;
00397 cacheEntry[var].older = -1;
00398 cacheEntry[var].newer = -1;
00399 }
00400 else
00401 {
00402 cacheEntry[cacheNewest].newer = var;
00403 cacheEntry[var].older = cacheNewest;
00404 cacheEntry[var].newer = -1;
00405 cacheNewest = var;
00406 }
00407 }
00408
00409 void CachedMatrix::cacheRemove(int var)
00410 {
00411 if (cacheEntry[var].older == -1)
00412 cacheOldest = cacheEntry[var].newer;
00413 else
00414 cacheEntry[cacheEntry[var].older].newer = cacheEntry[var].newer;
00415
00416 if (cacheEntry[var].newer == -1)
00417 cacheNewest = cacheEntry[var].older;
00418 else
00419 cacheEntry[cacheEntry[var].newer].older = cacheEntry[var].older;
00420
00421 cacheEntry[var].older = -2;
00422 cacheEntry[var].newer = -2;
00423 }
00424
00425 void CachedMatrix::cacheAdd(int var, unsigned int length)
00426 {
00427 cacheEntry[var].length = length;
00428 cacheEntry[var].data = (float*)(void*)malloc(length * sizeof(float));
00429 if (cacheEntry[var].data == NULL) throw SHARKEXCEPTION("[CachedMatrix::cacheAppend] out of memory error");
00430 cacheSize += length;
00431
00432 cacheAppend(var);
00433 }
00434
00435 void CachedMatrix::cacheDelete(int var)
00436 {
00437 free(cacheEntry[var].data);
00438 cacheSize -= cacheEntry[var].length;
00439
00440 cacheEntry[var].data = NULL;
00441 cacheEntry[var].length = 0;
00442
00443 cacheRemove(var);
00444 }
00445
00446 void CachedMatrix::cacheResize(int var, unsigned int newlength)
00447 {
00448 int diff = newlength - cacheEntry[var].length;
00449 if (diff == 0) return;
00450 cacheSize += diff;
00451 cacheEntry[var].length = newlength;
00452 cacheEntry[var].data = (float*)(void*)realloc((void*)cacheEntry[var].data, newlength * sizeof(float));
00453 if (cacheEntry[var].data == NULL) throw SHARKEXCEPTION("[CachedMatrix::cacheResize] out of memory error");
00454 }
00455
00456 void CachedMatrix::cacheClear()
00457 {
00458 unsigned int e, ec = cacheEntry.size();
00459 for (e = 0; e < ec; e++)
00460 {
00461 if (cacheEntry[e].data != NULL) free(cacheEntry[e].data);
00462 cacheEntry[e].data = NULL;
00463 cacheEntry[e].length = 0;
00464 cacheEntry[e].older = -2;
00465 cacheEntry[e].newer = -2;
00466 }
00467 cacheOldest = -1;
00468 cacheNewest = -1;
00469 cacheSize = 0;
00470 }
00471
00472
00474
00475
00476 void QpSvmCG::Solve(const Array<double>& quadratic,
00477 const Array<double>& linear,
00478 const Array<double>& boxMin,
00479 const Array<double>& boxMax,
00480 Array<double>& point,
00481 double accuracy)
00482 {
00483 SIZE_CHECK(quadratic.ndim() == 2);
00484 SIZE_CHECK(linear.ndim() == 1);
00485 SIZE_CHECK(boxMin.ndim() == 1);
00486 SIZE_CHECK(boxMax.ndim() == 1);
00487 SIZE_CHECK(point.ndim() == 1);
00488
00489 int dimension = quadratic.dim(0);
00490
00491 SIZE_CHECK((int)quadratic.dim(1) == dimension);
00492 SIZE_CHECK((int)linear.dim(0) == dimension);
00493 SIZE_CHECK((int)boxMin.dim(0) == dimension);
00494 SIZE_CHECK((int)boxMax.dim(0) == dimension);
00495 SIZE_CHECK((int)point.dim(0) == dimension);
00496
00497 int i, j;
00498 Array<double> direction(dimension);
00499 Array<bool> active(dimension);
00500 Array<double> gradient(dimension);
00501 Array<double> conjugate(dimension);
00502 conjugate = 0.0;
00503 double DirLen2 = 0.0;
00504 double DirLen2old = 0.0;
00505 double accuracy2 = accuracy * accuracy;
00506 bool changed, bounds_changed;
00507 int nActive = 0;
00508 int nUpdatesLeft = -1;
00509 int bound = -1;
00510 int nReset = 0;
00511 double step = 0.0;
00512 double clipped = 0.0;
00513 double value;
00514 double first = 0.0;
00515 double second = 0.0;
00516 double scp, sub;
00517 double norm2;
00518
00519 active = false;
00520
00521 int iter, maxiter = 10 * dimension * dimension;
00522 for (iter=0; iter<maxiter; iter++)
00523 {
00524 if (nUpdatesLeft == -1)
00525 {
00526
00527 for (i=0; i<dimension; i++)
00528 {
00529 value = linear(i);
00530 for (j=0; j<dimension; j++) value += quadratic(i, j) * point(j);
00531 gradient(i) = value;
00532 }
00533 nUpdatesLeft = 100;
00534 }
00535
00536
00537 scp = 0.0;
00538 for (i=0; i<dimension; i++)
00539 {
00540 if (active(i)) continue;
00541 scp += gradient(i);
00542 }
00543 sub = scp / (dimension - nActive);
00544 bounds_changed = false;
00545 do
00546 {
00547 changed = false;
00548 for (i=0; i<dimension; i++)
00549 {
00550 if (active(i))
00551 {
00552 double g = gradient(i) - (scp + gradient(i)) / (dimension - nActive + 1.0);
00553 if ((g <= 0.0 && point(i) == boxMin(i))
00554 || (g >= 0.0 && point(i) == boxMax(i)))
00555 {
00556 active(i) = false;
00557 nActive--;
00558 scp += gradient(i);
00559 sub = scp / (dimension - nActive);
00560 changed = true;
00561 }
00562 }
00563 else
00564 {
00565 double g = gradient(i) - sub;
00566 if ((g > 0.0 && point(i) == boxMin(i))
00567 || (g < 0.0 && point(i) == boxMax(i)))
00568 {
00569 active(i) = true;
00570 nActive++;
00571 scp -= gradient(i);
00572 sub = scp / (dimension - nActive);
00573 changed = true;
00574 }
00575 }
00576 }
00577 bounds_changed = bounds_changed || changed;
00578 }
00579 while (changed);
00580 if (bounds_changed && iter > 0) nReset = 0;
00581
00582
00583 if (nActive + 1 >= dimension) break;
00584
00585
00586
00587 DirLen2old = DirLen2;
00588 DirLen2 = 0.0;
00589 for (i=0; i<dimension; i++)
00590 {
00591 if (active(i)) continue;
00592 value = gradient(i) - sub;
00593 direction(i) = value;
00594 DirLen2 += value * value;
00595 }
00596
00597
00598 nReset--;
00599 if (nReset == 0)
00600 {
00601
00602
00603
00604 break;
00605 }
00606 else if (nReset < 0)
00607 {
00608
00609 conjugate = direction;
00610 nReset = dimension - 1 - nActive;
00611 }
00612 else
00613 {
00614 double beta = DirLen2 / DirLen2old;
00615 for (i=0; i<dimension; i++)
00616 {
00617 if (active(i)) continue;
00618 else conjugate(i) = direction(i) + beta * conjugate(i);
00619 }
00620 }
00621
00622
00623 first = 0.0;
00624 second = 0.0;
00625 norm2 = 0.0;
00626 for (i=0; i<dimension; i++)
00627 {
00628 if (active(i)) continue;
00629 double c = conjugate(i);
00630 double Qc = 0.0;
00631 for (j=0; j<dimension; j++)
00632 {
00633 if (active(j)) continue;
00634 Qc += quadratic(i, j) * conjugate(j);
00635 }
00636 first += gradient(i) * c;
00637 second += c * Qc;
00638 norm2 += c * c;
00639 }
00640 if (second <= 0.0) break;
00641 step = -first / second;
00642
00643
00644 if (nReset <= 1 && step * step * norm2 < accuracy2) break;
00645
00646
00647 bound = -1;
00648 clipped = step;
00649 for (i=0; i<dimension; i++)
00650 {
00651 if (active(i)) continue;
00652 if (point(i) + clipped * conjugate(i) > boxMax(i))
00653 {
00654 clipped = (boxMax(i) - point(i)) / conjugate(i);
00655 bound = i;
00656 }
00657 else if (point(i) + clipped * conjugate(i) < boxMin(i))
00658 {
00659 clipped = (boxMin(i) - point(i)) / conjugate(i);
00660 bound = i;
00661 }
00662 }
00663
00664
00665 if (5 * nActive > dimension && nUpdatesLeft > 0)
00666 {
00667
00668 for (i=0; i<dimension; i++)
00669 {
00670 if (active(i)) continue;
00671 double delta = clipped * conjugate(i);
00672 for (j=0; j<dimension; j++) gradient(j) += quadratic(i, j) * delta;
00673 }
00674 nUpdatesLeft--;
00675 }
00676 else nUpdatesLeft = -1;
00677
00678
00679 changed = false;
00680 for (i=0; i<dimension; i++)
00681 {
00682 if (active(i)) continue;
00683 double p = point(i);
00684 double newp = p + clipped * conjugate(i);
00685 point(i) = newp;
00686 if (p != newp) changed = true;
00687 }
00688
00689
00690 if (! changed) break;
00691
00692
00693 if (bound != -1)
00694 {
00695
00696
00697 double threshold = 0.5 * (boxMax(bound) + boxMin(bound));
00698 if (point(bound) > threshold) point(bound) = boxMax(bound);
00699 else point(bound) = boxMin(bound);
00700 nReset = 0;
00701 }
00702 }
00703
00704 if (iter >= maxiter)
00705 {
00706 throw SHARKEXCEPTION("QpSvmCG did not converge");
00707 printf("\n\n***************** QpSvmCG did not converge!!!\n\n");
00708 printf("boxMin:\n");
00709 writeArray(boxMin, std::cout);
00710 printf("boxMax:\n");
00711 writeArray(boxMax, std::cout);
00712 printf("point:\n");
00713 writeArray(point, std::cout);
00714 printf("gradient:\n");
00715 writeArray(gradient, std::cout);
00716 printf("direction:\n");
00717 writeArray(direction, std::cout);
00718 printf("conjugate:\n");
00719 writeArray(conjugate, std::cout);
00720 printf("active:\n");
00721 writeArray(active, std::cout);
00722 }
00723 }
00724
00725
00727
00728
00729 QpSvmDecomp::QpSvmDecomp(CachedMatrix& quadraticPart)
00730 : quadratic(quadraticPart)
00731 {
00732 printInfo = false;
00733 WSS_Strategy = NULL;
00734 useShrinking = true;
00735 maxIter = -1;
00736 maxSeconds = -1;
00737
00738 dimension = quadratic.getMatrixSize();
00739
00740
00741 alpha.resize(dimension, false);
00742 diagonal.resize(dimension, false);
00743 permutation.resize(dimension, false);
00744 gradient.resize(dimension, false);
00745 linear.resize(dimension, false);
00746 boxMin.resize(dimension, false);
00747 boxMax.resize(dimension, false);
00748
00749
00750 unsigned int i;
00751 for (i = 0; i < dimension; i++)
00752 {
00753 permutation(i) = i;
00754 diagonal(i) = quadratic.Entry(i, i);
00755 }
00756 }
00757
00758 QpSvmDecomp::~QpSvmDecomp()
00759 {
00760 }
00761
00762
00763 double QpSvmDecomp::Solve(const Array<double>& linearPart,
00764 const Array<double>& boxLower,
00765 const Array<double>& boxUpper,
00766 Array<double>& solutionVector,
00767 double eps,
00768 double threshold)
00769 {
00770 SIZE_CHECK(linearPart.ndim() == 1);
00771 SIZE_CHECK(boxLower.ndim() == 1);
00772 SIZE_CHECK(boxUpper.ndim() == 1);
00773 SIZE_CHECK(linearPart.dim(0) == dimension);
00774 SIZE_CHECK(boxLower.dim(0) == dimension);
00775 SIZE_CHECK(boxUpper.dim(0) == dimension);
00776
00777 unsigned int a, i, j;
00778 float* qi;
00779 float* qj;
00780
00781 for (i = 0; i < dimension; i++)
00782 {
00783 j = permutation(i);
00784 alpha(i) = solutionVector(j);
00785 linear(i) = linearPart(j);
00786 boxMin(i) = boxLower(j);
00787 boxMax(i) = boxUpper(j);
00788 }
00789
00790 epsilon = eps;
00791 optimal = false;
00792
00793
00794 active = dimension;
00795 gradient = linear;
00796
00797 for (i = 0; i < dimension; i++)
00798 {
00799 if (boxMax(i) < boxMin(i)) throw SHARKEXCEPTION("[QpSvmDecomp::Solve] The feasible region is empty.");
00800
00801 double v = alpha(i);
00802 if (v != 0.0)
00803 {
00804 qi = quadratic.Row(i, 0, dimension);
00805 for (a = 0; a < dimension; a++) gradient(a) -= qi[a] * v;
00806 }
00807 }
00808
00809 bFirst = true;
00810 bUnshrinked = false;
00811 unsigned int shrinkCounter = (active < 1000) ? active : 1000;
00812
00813 SelectWSS();
00814
00815
00816 if (printInfo) cout << "{" << flush;
00817 iter = 0;
00818 time_t starttime;
00819 time(&starttime);
00820 while (iter != maxIter)
00821 {
00822
00823 if (SelectWorkingSet(i, j))
00824 {
00825
00826 if (printInfo) cout << "*" << flush;
00827
00828 if (! useShrinking)
00829 {
00830 optimal = true;
00831 break;
00832 }
00833
00834
00835 Unshrink();
00836 shrinkCounter = 1;
00837
00838
00839 if (SelectWorkingSet(i, j))
00840 {
00841 optimal = true;
00842 break;
00843 }
00844 }
00845
00846
00847 {
00848 double ai = alpha(i);
00849 double aj = alpha(j);
00850 double Li = boxMin(i);
00851 double Ui = boxMax(i);
00852 double Lj = boxMin(j);
00853 double Uj = boxMax(j);
00854
00855
00856 qi = quadratic.Row(i, 0, active);
00857 qj = quadratic.Row(j, 0, active);
00858
00859
00860 double nominator = gradient(i) - gradient(j);
00861 double denominator = diagonal(i) + diagonal(j) - 2.0 * qi[j];
00862 double mu = nominator / denominator;
00863 if (ai + mu < Li) mu = Li - ai;
00864 else if (ai + mu > Ui) mu = Ui - ai;
00865 if (aj - mu < Lj) mu = aj - Lj;
00866 else if (aj - mu > Uj) mu = aj - Uj;
00867 alpha(i) += mu;
00868 alpha(j) -= mu;
00869
00870
00871 for (a = 0; a < active; a++) gradient(a) -= mu * (qi[a] - qj[a]);
00872 }
00873
00874 shrinkCounter--;
00875 if (shrinkCounter == 0)
00876 {
00877
00878 if (useShrinking) Shrink();
00879
00880 shrinkCounter = (active < 1000) ? active : 1000;
00881
00882 if (maxSeconds != -1)
00883 {
00884 time_t currenttime;
00885 time(¤ttime);
00886 if (currenttime - starttime > maxSeconds) break;
00887 }
00888 }
00889
00890 if (threshold < 1e100)
00891 {
00892 double objective = 0.0;
00893 for (i = 0; i < active; i++)
00894 {
00895 objective += (gradient(i) + linear(i)) * alpha(i);
00896 }
00897 objective *= 0.5;
00898 if (objective > threshold) break;
00899 }
00900
00901 iter++;
00902 if (printInfo)
00903 {
00904 if ((iter & 1023) == 0) cout << "." << flush;
00905 }
00906 }
00907 if (printInfo) cout << endl << "} #iterations=" << (long int)iter << endl;
00908
00909 Unshrink(true);
00910
00911
00912 double objective = 0.0;
00913 for (i = 0; i < dimension; i++)
00914 {
00915 solutionVector(permutation(i)) = alpha(i);
00916 objective += (gradient(i) + linear(i)) * alpha(i);
00917 }
00918 return 0.5 * objective;
00919 }
00920
00921 double QpSvmDecomp::ComputeInnerProduct(unsigned int index, const Array<double>& coeff)
00922 {
00923 unsigned int e = permutation(index);
00924 unsigned int i;
00925 unsigned int j;
00926 double ret = 0.0;
00927 double c;
00928 unsigned int crs_j, crs_e = quadratic.getCacheRowSize(e);
00929
00930 for (i = 0; i < dimension; i++)
00931 {
00932 j = permutation(i);
00933 c = coeff(j);
00934 if (c != 0.0)
00935 {
00936 if (j < crs_e) ret += c * quadratic.Row(e, 0, crs_e)[j];
00937 else
00938 {
00939 crs_j = quadratic.getCacheRowSize(j);
00940 if (e < crs_j) ret += c * quadratic.Row(j, 0, crs_j)[e];
00941 else ret += c * quadratic.Entry(j, e);
00942 }
00943 }
00944 }
00945
00946 return ret;
00947 }
00948
00949 void QpSvmDecomp::getGradient(Array<double>& grad)
00950 {
00951 grad.resize(dimension, false);
00952 unsigned int i;
00953 for (i = 0; i < dimension; i++) grad(permutation(i)) = gradient(i);
00954 }
00955
00956 bool QpSvmDecomp::MVP(unsigned int& i, unsigned int& j)
00957 {
00958 double largestUp = -1e100;
00959 double smallestDown = 1e100;
00960 unsigned int a;
00961
00962 for (a = 0; a < active; a++)
00963 {
00964 if (alpha(a) < boxMax(a))
00965 {
00966 if (gradient(a) > largestUp)
00967 {
00968 largestUp = gradient(a);
00969 i = a;
00970 }
00971 }
00972 if (alpha(a) > boxMin(a))
00973 {
00974 if (gradient(a) < smallestDown)
00975 {
00976 smallestDown = gradient(a);
00977 j = a;
00978 }
00979 }
00980 }
00981
00982
00983 return (largestUp - smallestDown < epsilon);
00984 }
00985
00986 bool QpSvmDecomp::HMG(unsigned int& i, unsigned int& j)
00987 {
00988 if (bFirst)
00989 {
00990
00991 bFirst = false;
00992
00993 return Libsvm28(i, j);
00994 }
00995
00996
00997 {
00998 double Li = boxMin(old_i);
00999 double Ui = boxMax(old_i);
01000 double Lj = boxMin(old_j);
01001 double Uj = boxMax(old_j);
01002 double eps_i = 1e-8 * (Ui - Li);
01003 double eps_j = 1e-8 * (Uj - Lj);
01004 if ((alpha(old_i) <= Li + eps_i || alpha(old_i) >= Ui - eps_i)
01005 && ((alpha(old_j) <= Lj + eps_j || alpha(old_j) >= Uj - eps_j)))
01006 {
01007 if (printInfo) cout << "^" << flush;
01008
01009 return Libsvm28(i, j);
01010 }
01011 }
01012
01013
01014 unsigned int a;
01015 double aa, ab;
01016 double da, db;
01017 double ga, gb;
01018 double gain;
01019 double La, Ua, Lb, Ub;
01020 double denominator;
01021 float* q;
01022 double mu_max, mu_star;
01023
01024 double best = 0.0;
01025 double mu_best = 0.0;
01026
01027
01028 q = quadratic.Row(old_i, 0, active);
01029 ab = alpha(old_i);
01030 db = diagonal(old_i);
01031 Lb = boxMin(old_i);
01032 Ub = boxMax(old_i);
01033 gb = gradient(old_i);
01034 for (a = 0; a < active; a++)
01035 {
01036 if (a == old_i || a == old_j) continue;
01037
01038 aa = alpha(a);
01039 da = diagonal(a);
01040 La = boxMin(a);
01041 Ua = boxMax(a);
01042 ga = gradient(a);
01043
01044 denominator = (da + db - 2.0 * q[a]);
01045 mu_max = (ga - gb) / denominator;
01046 mu_star = mu_max;
01047
01048 if (aa + mu_star < La) mu_star = La - aa;
01049 else if (mu_star + aa > Ua) mu_star = Ua - aa;
01050 if (ab - mu_star < Lb) mu_star = ab - Lb;
01051 else if (ab - mu_star > Ub) mu_star = ab - Ub;
01052
01053 gain = mu_star * (2.0 * mu_max - mu_star) * denominator;
01054
01055
01056 if (gain > best)
01057 {
01058 best = gain;
01059 mu_best = mu_star;
01060 i = a;
01061 j = old_i;
01062 }
01063 }
01064
01065
01066 q = quadratic.Row(old_j, 0, active);
01067 ab = alpha(old_j);
01068 db = diagonal(old_j);
01069 Lb = boxMin(old_j);
01070 Ub = boxMax(old_j);
01071 gb = gradient(old_j);
01072 for (a = 0; a < active; a++)
01073 {
01074 if (a == old_i || a == old_j) continue;
01075
01076 aa = alpha(a);
01077 da = diagonal(a);
01078 La = boxMin(a);
01079 Ua = boxMax(a);
01080 ga = gradient(a);
01081
01082 denominator = (da + db - 2.0 * q[a]);
01083 mu_max = (ga - gb) / denominator;
01084 mu_star = mu_max;
01085
01086 if (aa + mu_star < La) mu_star = La - aa;
01087 else if (mu_star + aa > Ua) mu_star = Ua - aa;
01088 if (ab - mu_star < Lb) mu_star = ab - Lb;
01089 else if (ab - mu_star > Ub) mu_star = ab - Ub;
01090
01091 gain = mu_star * (2.0 * mu_max - mu_star) * denominator;
01092
01093
01094 if (gain > best)
01095 {
01096 best = gain;
01097 mu_best = mu_star;
01098 i = a;
01099 j = old_j;
01100 }
01101 }
01102
01103
01104 return (fabs(mu_best) < epsilon);
01105 }
01106
01107 bool QpSvmDecomp::Libsvm28(unsigned int& i, unsigned int& j)
01108 {
01109 i = 0;
01110 j = 1;
01111
01112 double largestUp = -1e100;
01113 double smallestDown = 1e100;
01114 unsigned int a;
01115
01116
01117 for (a = 0; a < active; a++)
01118 {
01119 if (alpha(a) < boxMax(a))
01120 {
01121 if (gradient(a) > largestUp)
01122 {
01123 largestUp = gradient(a);
01124 i = a;
01125 }
01126 }
01127 }
01128
01129
01130 float* q = quadratic.Row(i, 0, active);
01131 double best = 0.0;
01132 for (a = 0; a < active; a++)
01133 {
01134 if (alpha(a) > boxMin(a))
01135 {
01136 if (gradient(a) < smallestDown) smallestDown = gradient(a);
01137
01138 double grad_diff = largestUp - gradient(a);
01139 if (grad_diff > 0.0)
01140 {
01141 double quad_coef = diagonal(i) + diagonal(a) - 2.0 * q[a];
01142 if (quad_coef == 0.0) continue;
01143 double obj_diff = (grad_diff * grad_diff) / quad_coef;
01144
01145 if (obj_diff > best)
01146 {
01147 best = obj_diff;
01148 j = a;
01149 }
01150 }
01151 }
01152 }
01153
01154
01155 return (largestUp - smallestDown < epsilon);
01156 }
01157
01158 bool QpSvmDecomp::SelectWorkingSet(unsigned int& i, unsigned int& j)
01159 {
01160
01161 bool ret = (this->*(this->currentWSS))(i, j);
01162
01163 old_i = i;
01164 old_j = j;
01165 return ret;
01166 }
01167
01168 void QpSvmDecomp::SelectWSS()
01169 {
01170 if (WSS_Strategy != NULL && strcmp(WSS_Strategy, "MVP") == 0)
01171 {
01172
01173 currentWSS = &QpSvmDecomp::MVP;
01174 }
01175 else if (WSS_Strategy != NULL && strcmp(WSS_Strategy, "HMG") == 0)
01176 {
01177
01178 currentWSS = &QpSvmDecomp::HMG;
01179 }
01180 else if (WSS_Strategy != NULL && strcmp(WSS_Strategy, "LIBSVM28") == 0)
01181 {
01182
01183 currentWSS = &QpSvmDecomp::Libsvm28;
01184 }
01185 else
01186 {
01187
01188
01189
01190 if (active * active > quadratic.getMaxCacheSize())
01191 currentWSS = &QpSvmDecomp::HMG;
01192 else
01193 currentWSS = &QpSvmDecomp::Libsvm28;
01194 }
01195 }
01196
01197 void QpSvmDecomp::Shrink()
01198 {
01199 double largestUp = -1e100;
01200 double smallestDown = 1e100;
01201 std::vector<unsigned int> shrinked;
01202 unsigned int a;
01203 double v, g;
01204
01205 for (a = 0; a < active; a++)
01206 {
01207 v = alpha(a);
01208 g = gradient(a);
01209 if (v > boxMin(a))
01210 {
01211 if (g < smallestDown) smallestDown = g;
01212 }
01213 if (v < boxMax(a))
01214 {
01215 if (g > largestUp) largestUp = g;
01216 }
01217 }
01218
01219 if (! bUnshrinked && (largestUp - smallestDown < 10.0 * epsilon))
01220 {
01221
01222 if (printInfo) cout << "#" << flush;
01223 Unshrink();
01224 bUnshrinked = true;
01225 SelectWSS();
01226 return;
01227 }
01228
01229
01230 for (a = 0; a < active; a++)
01231 {
01232 if (a == old_i) continue;
01233 if (a == old_j) continue;
01234 v = alpha(a);
01235 g = gradient(a);
01236
01237 if (v == boxMin(a))
01238 {
01239 if (g > smallestDown) continue;
01240 }
01241 else if (v == boxMax(a))
01242 {
01243 if (g < largestUp) continue;
01244 }
01245 else continue;
01246
01247
01248
01249 shrinked.push_back(a);
01250 if (quadratic.getCacheRowSize(a) > 0) quadratic.CacheRowRelease(a);
01251 }
01252
01253 int s, sc = shrinked.size();
01254 if (sc == 0)
01255 {
01256 return;
01257 }
01258 unsigned int new_active = active - sc;
01259
01260
01261
01262 unsigned int k, high = active;
01263 for (s = sc - 1; s >= 0; s--)
01264 {
01265 k = shrinked[s];
01266 high--;
01267
01268
01269 FlipCoordinates(k, high);
01270 }
01271
01272
01273 for (a = 0; a < active; a++)
01274 {
01275 if (quadratic.getCacheRowSize(a) > new_active) quadratic.CacheRowResize(a, new_active);
01276 }
01277
01278 active = new_active;
01279
01280 SelectWSS();
01281 }
01282
01283 void QpSvmDecomp::Unshrink(bool complete)
01284 {
01285 if (printInfo) cout << "[" << flush;
01286 if (active == dimension)
01287 {
01288 if (printInfo) cout << "]" << flush;
01289 return;
01290 }
01291
01292 unsigned int i, a;
01293 float* q;
01294 double v, g;
01295 double largestUp = -1e100;
01296 double smallestDown = 1e100;
01297
01298
01299 for (a = active; a < dimension; a++) gradient(a) = linear(a);
01300 for (i = 0; i < dimension; i++)
01301 {
01302 v = alpha(i);
01303 if (v == 0.0) continue;
01304
01305 q = quadratic.Row(i, active, dimension, true);
01306 for (a = active; a < dimension; a++) gradient(a) -= q[a] * v;
01307 }
01308
01309 if (complete)
01310 {
01311 active = dimension;
01312 if (printInfo) cout << "]" << flush;
01313 return;
01314 }
01315
01316
01317 for (a = 0; a < dimension; a++)
01318 {
01319 g = gradient(a);
01320 v = alpha(a);
01321
01322 if (v > boxMin(a) && g < smallestDown) smallestDown = g;
01323 if (v < boxMax(a) && g > largestUp) largestUp = g;
01324 }
01325
01326
01327 for (a = active; a < dimension; a++)
01328 {
01329 if (a == old_i) continue;
01330 if (a == old_j) continue;
01331 g = gradient(a);
01332 v = alpha(a);
01333
01334 if (v == boxMin(a))
01335 {
01336 if (g <= smallestDown) continue;
01337 }
01338 else if (v == boxMax(a))
01339 {
01340 if (g >= largestUp) continue;
01341 }
01342
01343 FlipCoordinates(active, a);
01344 active++;
01345 }
01346
01347 if (printInfo) cout << active << "]" << flush;
01348 }
01349
01350 void QpSvmDecomp::FlipCoordinates(unsigned int i, unsigned int j)
01351 {
01352 if (i == j) return;
01353
01354
01355 if (old_i == i) old_i = j;
01356 else if (old_i == j) old_i = i;
01357
01358 if (old_j == i) old_j = j;
01359 else if (old_j == j) old_j = i;
01360
01361
01362 XCHG_A(double, boxMin, i, j);
01363 XCHG_A(double, boxMax, i, j);
01364 XCHG_A(double, linear, i, j);
01365 XCHG_A(double, alpha, i, j);
01366 XCHG_A(unsigned int, permutation, i, j);
01367 XCHG_A(double, diagonal, i, j);
01368 XCHG_A(double, gradient, i, j);
01369
01370
01371 quadratic.FlipColumnsAndRows(i, j);
01372 }
01373
01374
01376
01377
01378 QpBoxDecomp::QpBoxDecomp(CachedMatrix& quadraticPart)
01379 : quadratic(quadraticPart)
01380 {
01381 dimension = quadratic.getMatrixSize();
01382
01383
01384 alpha.resize(dimension, false);
01385 diagonal.resize(dimension, false);
01386 permutation.resize(dimension, false);
01387 gradient.resize(dimension, false);
01388 linear.resize(dimension, false);
01389 boxMin.resize(dimension, false);
01390 boxMax.resize(dimension, false);
01391
01392
01393 unsigned int i;
01394 for (i = 0; i < dimension; i++)
01395 {
01396 permutation(i) = i;
01397 diagonal(i) = quadratic.Entry(i, i);
01398 }
01399
01400 maxIter = -1;
01401 }
01402
01403 QpBoxDecomp::~QpBoxDecomp()
01404 {
01405 }
01406
01407
01408 void QpBoxDecomp::Solve(const Array<double>& linearPart,
01409 const Array<double>& boxLower,
01410 const Array<double>& boxUpper,
01411 Array<double>& solutionVector,
01412 double eps)
01413 {
01414 SIZE_CHECK(linearPart.ndim() == 1);
01415 SIZE_CHECK(boxLower.ndim() == 1);
01416 SIZE_CHECK(boxUpper.ndim() == 1);
01417 SIZE_CHECK(linearPart.dim(0) == dimension);
01418 SIZE_CHECK(boxLower.dim(0) == dimension);
01419 SIZE_CHECK(boxUpper.dim(0) == dimension);
01420
01421 unsigned int a, i, j;
01422 float* q;
01423
01424 for (i = 0; i < dimension; i++)
01425 {
01426 j = permutation(i);
01427 alpha(i) = solutionVector(j);
01428 linear(i) = linearPart(j);
01429 boxMin(i) = boxLower(j);
01430 boxMax(i) = boxUpper(j);
01431 }
01432
01433 epsilon = eps;
01434
01435
01436 active = dimension;
01437 gradient = linear;
01438
01439 for (i = 0; i < dimension; i++)
01440 {
01441 if (boxMax(i) < boxMin(i)) throw SHARKEXCEPTION("[QpBoxDecomp::Solve] The feasible region is empty.");
01442
01443 double v = alpha(i);
01444 if (v != 0.0)
01445 {
01446 q = quadratic.Row(i, 0, dimension);
01447 for (a = 0; a < dimension; a++) gradient(a) -= q[a] * v;
01448 }
01449 }
01450
01451
01452 Shrink();
01453
01454
01455 SMO();
01456
01457
01458 for (i = 0; i < dimension; i++)
01459 {
01460 solutionVector(permutation(i)) = alpha(i);
01461 }
01462 }
01463
01464 void QpBoxDecomp::Continue(const Array<double>& boxLower,
01465 const Array<double>& boxUpper,
01466 Array<double>& solutionVector)
01467 {
01468 SIZE_CHECK(boxLower.ndim() == 1);
01469 SIZE_CHECK(boxUpper.ndim() == 1);
01470 SIZE_CHECK(boxLower.dim(0) == dimension);
01471 SIZE_CHECK(boxUpper.dim(0) == dimension);
01472 solutionVector.resize(alpha.dim(0), false);
01473
01474 unsigned int i, j;
01475
01476 for (i = 0; i < dimension; i++)
01477 {
01478 j = permutation(i);
01479 boxMin(i) = boxLower(j);
01480 boxMax(i) = boxUpper(j);
01481 }
01482
01483
01484 Shrink();
01485
01486
01487 SMO();
01488
01489
01490 for (i = 0; i < dimension; i++)
01491 {
01492 solutionVector(permutation(i)) = alpha(i);
01493 }
01494 }
01495
01496 void QpBoxDecomp::Continue(const Array<double>& gradientUpdate,
01497 Array<double>& solutionVector)
01498 {
01499 SIZE_CHECK(gradientUpdate.ndim() == 1);
01500 SIZE_CHECK(gradientUpdate.dim(0) == dimension);
01501 solutionVector.resize(alpha.dim(0), false);
01502
01503 unsigned int i;
01504
01505
01506 for (i=0; i<dimension; i++) gradient(i) = gradientUpdate(permutation(i));
01507
01508
01509 Unshrink(false);
01510
01511
01512 SMO();
01513
01514
01515 for (i=0; i < dimension; i++) solutionVector(permutation(i)) = alpha(i);
01516 }
01517
01518 void QpBoxDecomp::SMO()
01519 {
01520 unsigned int a, i;
01521 float* q;
01522
01523 bUnshrinked = false;
01524 unsigned int shrinkCounter = (active < 1000) ? active : 1000;
01525
01526
01527 iter = 0;
01528 optimal = false;
01529 while (iter != maxIter)
01530 {
01531
01532 if (SelectWorkingSet(i))
01533 {
01534
01535
01536
01537 Unshrink(true);
01538
01539
01540 if (SelectWorkingSet(i))
01541 {
01542 optimal = true;
01543 break;
01544 }
01545
01546
01547 Shrink();
01548 shrinkCounter = (active < 1000) ? active : 1000;
01549 }
01550
01551
01552 {
01553 double ai = alpha(i);
01554 double Li = boxMin(i);
01555 double Ui = boxMax(i);
01556
01557
01558 double nominator = gradient(i);
01559 double denominator = diagonal(i);
01560 double mu = nominator / denominator;
01561 if (ai + mu < Li) mu = Li - ai;
01562 else if (ai + mu > Ui) mu = Ui - ai;
01563 alpha(i) += mu;
01564
01565
01566 q = quadratic.Row(i, 0, active);
01567
01568
01569 for (a = 0; a < active; a++) gradient(a) -= mu * q[a];
01570 }
01571
01572 shrinkCounter--;
01573 if (shrinkCounter == 0)
01574 {
01575
01576 Shrink();
01577
01578 shrinkCounter = (active < 1000) ? active : 1000;
01579 }
01580
01581 iter++;
01582 }
01583 }
01584
01585 bool QpBoxDecomp::SelectWorkingSet(unsigned int& i)
01586 {
01587 double largest = 0.0;
01588 unsigned int a;
01589
01590 for (a = 0; a < active; a++)
01591 {
01592 double v = alpha(a);
01593 double g = gradient(a);
01594 if (v < boxMax(a))
01595 {
01596 if (g > largest)
01597 {
01598 largest = g;
01599 i = a;
01600 }
01601 }
01602 if (v > boxMin(a))
01603 {
01604 if (-g > largest)
01605 {
01606 largest = -g;
01607 i = a;
01608 }
01609 }
01610 }
01611
01612
01613 return (largest < epsilon);
01614 }
01615
01616 void QpBoxDecomp::Shrink()
01617 {
01618 std::vector<unsigned int> shrinked;
01619 unsigned int a;
01620 double v, g;
01621
01622 if (! bUnshrinked)
01623 {
01624 double largest = 0.0;
01625 for (a = 0; a < active; a++)
01626 {
01627 if (alpha(a) < boxMax(a))
01628 {
01629 if (gradient(a) > largest)
01630 {
01631 largest = gradient(a);
01632 }
01633 }
01634 if (alpha(a) > boxMin(a))
01635 {
01636 if (-gradient(a) > largest)
01637 {
01638 largest = -gradient(a);
01639 }
01640 }
01641 }
01642
01643 if (largest < 10.0 * epsilon)
01644 {
01645
01646 Unshrink(true);
01647 bUnshrinked = true;
01648 }
01649 }
01650
01651
01652 for (a = 0; a < active; a++)
01653 {
01654 v = alpha(a);
01655 g = gradient(a);
01656
01657 if ((v == boxMin(a) && g <= 0.0) || (v == boxMax(a) && g >= 0.0))
01658 {
01659
01660
01661 shrinked.push_back(a);
01662 if (quadratic.getCacheRowSize(a) > 0) quadratic.CacheRowRelease(a);
01663 }
01664 }
01665
01666 int s, sc = shrinked.size();
01667 if (sc == 0) return;
01668
01669 unsigned int new_active = active - sc;
01670
01671
01672
01673 unsigned int k, high = active;
01674 for (s = sc - 1; s >= 0; s--)
01675 {
01676 k = shrinked[s];
01677 high--;
01678
01679
01680 FlipCoordinates(k, high);
01681 }
01682
01683
01684 for (a = 0; a < active; a++)
01685 {
01686 if (quadratic.getCacheRowSize(a) > new_active) quadratic.CacheRowResize(a, new_active);
01687 }
01688
01689 active = new_active;
01690 }
01691
01692 void QpBoxDecomp::Unshrink(bool complete)
01693 {
01694 if (active == dimension) return;
01695
01696 unsigned int i, a;
01697 float* q;
01698 double v;
01699
01700
01701 for (a = active; a < dimension; a++) gradient(a) = linear(a);
01702 for (i = 0; i < dimension; i++)
01703 {
01704 v = alpha(i);
01705 if (v == 0.0) continue;
01706
01707 q = quadratic.Row(i, active, dimension, true);
01708 for (a = active; a < dimension; a++) gradient(a) -= q[a] * v;
01709 }
01710
01711 active = dimension;
01712 if (! complete) Shrink();
01713 }
01714
01715 void QpBoxDecomp::FlipCoordinates(unsigned int i, unsigned int j)
01716 {
01717 if (i == j) return;
01718
01719
01720 XCHG_A(double, boxMin, i, j);
01721 XCHG_A(double, boxMax, i, j);
01722 XCHG_A(double, linear, i, j);
01723 XCHG_A(double, alpha, i, j);
01724 XCHG_A(unsigned int, permutation, i, j);
01725 XCHG_A(double, diagonal, i, j);
01726 XCHG_A(double, gradient, i, j);
01727
01728
01729 quadratic.FlipColumnsAndRows(i, j);
01730 }
01731
01732
01734
01735
01736 QpBoxAllInOneDecomp::QpBoxAllInOneDecomp(CachedMatrix& kernel)
01737 : kernelMatrix(kernel)
01738 {
01739 examples = kernelMatrix.getMatrixSize();
01740 maxIter = -1;
01741 }
01742
01743 QpBoxAllInOneDecomp::~QpBoxAllInOneDecomp()
01744 {
01745 }
01746
01747
01748 void QpBoxAllInOneDecomp::Solve(unsigned int classes,
01749 const Array<double>& target,
01750 const Array<double>& prototypes,
01751 double C,
01752 Array<double>& solutionVector,
01753 double eps)
01754 {
01755 SIZE_CHECK(target.ndim() == 2);
01756
01757 this->classes = classes;
01758 variables = examples * classes;
01759
01760 SIZE_CHECK(target.dim(0) == examples);
01761 SIZE_CHECK(target.dim(1) == 1);
01762
01763 unsigned int a, b, bc, i, j;
01764 float* q = NULL;
01765
01766
01767
01768 m_prototypeProduct.resize(classes, classes, false);
01769 m_prototypeLength.resize(classes, classes, false);
01770 for (a=0; a<classes; a++)
01771 {
01772 for (b=0; b<=a; b++)
01773 {
01774 m_prototypeProduct(a, b) = m_prototypeProduct(b, a)
01775 = scalarProduct(prototypes[a], prototypes[b]);
01776 Array<double> diff = prototypes[a] - prototypes[b];
01777 m_prototypeLength(a, b) = m_prototypeLength(b, a)
01778 = sqrt(scalarProduct(diff, diff));
01779 }
01780 }
01781
01782
01783 alpha.resize(variables, false);
01784 diagonal.resize(examples, false);
01785 gradient.resize(variables, false);
01786 linear.resize(variables, false);
01787 boxMin.resize(variables, false);
01788 boxMax.resize(variables, false);
01789 example.resize(examples);
01790 variable.resize(variables);
01791 storage.resize(variables);
01792
01793
01794 for (i = 0; i < examples; i++)
01795 {
01796 diagonal(i) = kernelMatrix.Entry(i, i);
01797 example[i].index = i;
01798 example[i].label = (unsigned int)target(i, 0);
01799 example[i].active = classes;
01800 example[i].variables = &storage[classes * i];
01801 }
01802 for (i = 0; i < variables; i++)
01803 {
01804 variable[i].example = i / classes;
01805 variable[i].index = i % classes;
01806 variable[i].label = i % classes;
01807 storage[i] = i;
01808 }
01809
01810
01811 for (a = 0; a < examples; a++)
01812 {
01813 unsigned int y = example[a].label;
01814 for (b = 0; b < classes; b++)
01815 {
01816 j = example[a].variables[b];
01817 unsigned int v = variable[j].label;
01818 alpha(j) = solutionVector(j);
01819 linear(j) = 1.0;
01820 boxMin(j) = 0.0;
01821 if (y == v) boxMax(j) = 0.0;
01822 else boxMax(j) = C;
01823 }
01824 }
01825 gradient = linear;
01826
01827 epsilon = eps;
01828
01829 activeEx = examples;
01830 activeVar = variables;
01831
01832 unsigned int e = 0xffffffff;
01833 for (i = 0; i < variables; i++)
01834 {
01835 if (boxMax(i) < boxMin(i)) throw SHARKEXCEPTION("[QpBoxAllInOneDecomp::Solve] The feasible region is empty.");
01836
01837 double v = alpha(i);
01838 if (v != 0.0)
01839 {
01840 unsigned int ei = variable[i].example;
01841 unsigned int vi = variable[i].label;
01842 unsigned int yi = example[ei].label;
01843 if (ei != e)
01844 {
01845 q = kernelMatrix.Row(ei, 0, activeEx);
01846 e = ei;
01847 }
01848
01849 for (a = 0; a < activeEx; a++)
01850 {
01851 double k = q[a];
01852 tExample* ex = &example[a];
01853 bc = ex->active;
01854 for (b = 0; b < bc; b++)
01855 {
01856 j = ex->variables[b];
01857 unsigned int vj = variable[j].label;
01858 unsigned int yj = ex->label;
01859 double km = Modifier(vi, vj, yi, yj);
01860 gradient(j) -= v * km * k;
01861 }
01862 }
01863 }
01864 }
01865
01866
01867 Shrink();
01868
01869 bUnshrinked = false;
01870 unsigned int shrinkCounter = (activeVar < 1000) ? activeVar : 1000;
01871
01872
01873 iter = 0;
01874 optimal = false;
01875 while (iter != maxIter)
01876 {
01877
01878 if (SelectWorkingSet(i))
01879 {
01880
01881
01882
01883 Unshrink(true);
01884
01885
01886 if (SelectWorkingSet(i))
01887 {
01888 optimal = true;
01889 break;
01890 }
01891
01892
01893 Shrink();
01894 shrinkCounter = (activeVar < 1000) ? activeVar : 1000;
01895 }
01896
01897
01898 {
01899 double ai = alpha(i);
01900 double Li = boxMin(i);
01901 double Ui = boxMax(i);
01902 unsigned int ei = variable[i].example;
01903 unsigned int vi = variable[i].label;
01904 unsigned int yi = example[ei].label;
01905
01906
01907 double km = Modifier(vi, vi, yi, yi);
01908 double nominator = gradient(i);
01909 double denominator = km * diagonal(ei);
01910 double mu = nominator / denominator;
01911 if (ai + mu < Li) mu = Li - ai;
01912 else if (ai + mu > Ui) mu = Ui - ai;
01913 alpha(i) += mu;
01914
01915
01916 q = kernelMatrix.Row(ei, 0, activeEx);
01917
01918
01919 for (a = 0; a < activeEx; a++)
01920 {
01921 double k = q[a];
01922 tExample* ex = &example[a];
01923 bc = ex->active;
01924 for (b = 0; b < bc; b++)
01925 {
01926 j = ex->variables[b];
01927
01928 unsigned int vj = variable[j].label;
01929 unsigned int yj = ex->label;
01930 double km = Modifier(vi, vj, yi, yj);
01931 gradient(j) -= mu * km * k;
01932 }
01933 }
01934 }
01935
01936 shrinkCounter--;
01937 if (shrinkCounter == 0)
01938 {
01939
01940 Shrink();
01941
01942 shrinkCounter = (activeVar < 1000) ? activeVar : 1000;
01943 }
01944
01945 iter++;
01946 }
01947
01948
01949 for (i = 0; i < variables; i++)
01950 {
01951 unsigned int j = classes * example[variable[i].example].index + variable[i].label;
01952 solutionVector(j) = alpha(i);
01953 }
01954 }
01955
01956 void QpBoxAllInOneDecomp::Continue(double largerC, Array<double>& solutionVector)
01957 {
01958 unsigned int a, b, bc, i = 0, j;
01959 float* q = NULL;
01960
01961 solutionVector.resize(variables, false);
01962
01963
01964 for (a = 0; a < variables; a++)
01965 {
01966 if (boxMax(a) > 0.0) boxMax(a) = largerC;
01967 }
01968
01969
01970
01971
01972
01973 bUnshrinked = false;
01974 unsigned int shrinkCounter = (activeVar < 1000) ? activeVar : 1000;
01975
01976
01977 while (true)
01978 {
01979
01980 if (SelectWorkingSet(i))
01981 {
01982
01983
01984
01985 Unshrink(true);
01986
01987
01988 if (SelectWorkingSet(i)) break;
01989
01990
01991 Shrink();
01992 shrinkCounter = (activeVar < 1000) ? activeVar : 1000;
01993 }
01994
01995
01996 {
01997 double ai = alpha(i);
01998 double Li = boxMin(i);
01999 double Ui = boxMax(i);
02000 unsigned int ei = variable[i].example;
02001 unsigned int vi = variable[i].label;
02002 unsigned int yi = example[ei].label;
02003
02004
02005 double km = Modifier(vi, vi, yi, yi);
02006 double nominator = gradient(i);
02007 double denominator = km * diagonal(ei);
02008 double mu = nominator / denominator;
02009 if (ai + mu < Li) mu = Li - ai;
02010 else if (ai + mu > Ui) mu = Ui - ai;
02011 alpha(i) += mu;
02012
02013
02014 q = kernelMatrix.Row(ei, 0, activeEx);
02015
02016
02017 for (a = 0; a < activeEx; a++)
02018 {
02019 double k = q[a];
02020 tExample* ex = &example[a];
02021 bc = ex->active;
02022 for (b = 0; b < bc; b++)
02023 {
02024 j = ex->variables[b];
02025
02026 unsigned int vj = variable[j].label;
02027 unsigned int yj = ex->label;
02028 double km = Modifier(vi, vj, yi, yj);
02029 gradient(j) -= mu * km * k;
02030 }
02031 }
02032 }
02033
02034 shrinkCounter--;
02035 if (shrinkCounter == 0)
02036 {
02037
02038 Shrink();
02039
02040 shrinkCounter = (activeVar < 1000) ? activeVar : 1000;
02041 }
02042
02043 iter++;
02044 }
02045
02046
02047 for (i = 0; i < variables; i++)
02048 {
02049 unsigned int j = classes * example[variable[i].example].index + variable[i].label;
02050 solutionVector(j) = alpha(i);
02051 }
02052 }
02053
02054 double QpBoxAllInOneDecomp::Modifier(unsigned int v_i, unsigned int v_j, unsigned int y_i, unsigned int y_j)
02055 {
02056 double p = m_prototypeProduct(y_i, y_j) - m_prototypeProduct(v_i, y_j) - m_prototypeProduct(y_i, v_j) + m_prototypeProduct(v_i, v_j);
02057
02058 if (p == 0.0) return 0.0;
02059 p /= (m_prototypeLength(y_i, v_i) * m_prototypeLength(y_j, v_j));
02060 return p;
02061 }
02062
02063 bool QpBoxAllInOneDecomp::SelectWorkingSet(unsigned int& i)
02064 {
02065 double largest = 0.0;
02066 unsigned int a;
02067
02068 for (a = 0; a < activeVar; a++)
02069 {
02070 double v = alpha(a);
02071 double g = gradient(a);
02072 if (v < boxMax(a))
02073 {
02074 if (g > largest)
02075 {
02076 largest = g;
02077 i = a;
02078 }
02079 }
02080 if (v > boxMin(a))
02081 {
02082 if (-g > largest)
02083 {
02084 largest = -g;
02085 i = a;
02086 }
02087 }
02088 }
02089
02090
02091 return (largest < epsilon);
02092 }
02093
02094 void QpBoxAllInOneDecomp::Shrink()
02095 {
02096 int a;
02097 double v, g;
02098
02099 if (! bUnshrinked)
02100 {
02101 double largest = 0.0;
02102 for (a = 0; a < (int)activeVar; a++)
02103 {
02104 if (alpha(a) < boxMax(a))
02105 {
02106 if (gradient(a) > largest) largest = gradient(a);
02107 }
02108 if (alpha(a) > boxMin(a))
02109 {
02110 if (-gradient(a) > largest) largest = -gradient(a);
02111 }
02112 }
02113 if (largest < 10.0 * epsilon)
02114 {
02115
02116 Unshrink(true);
02117 bUnshrinked = true;
02118 }
02119 }
02120
02121
02122 bool se = false;
02123 for (a = activeVar-1; a >= 0; a--)
02124 {
02125 v = alpha(a);
02126 g = gradient(a);
02127
02128 if ((v == boxMin(a) && g <= 0.0) || (v == boxMax(a) && g >= 0.0))
02129 {
02130
02131
02132 unsigned int e = variable[a].example;
02133 DeactivateVariable(a);
02134 if (example[e].active == 0)
02135 {
02136 se = true;
02137 }
02138 }
02139 }
02140
02141 if (se)
02142 {
02143
02144
02145 for (a = activeEx-1; a >= 0; a--)
02146 {
02147 if (example[a].active == 0) DeactivateExample(a);
02148 }
02149
02150
02151 for (a = 0; a < (int)activeEx; a++)
02152 {
02153 if (kernelMatrix.getCacheRowSize(a) > activeEx) kernelMatrix.CacheRowResize(a, activeEx);
02154 }
02155 }
02156 }
02157
02158 void QpBoxAllInOneDecomp::Unshrink(bool complete)
02159 {
02160 if (activeVar == variables) return;
02161
02162 unsigned int i, a;
02163 float* q;
02164 double v;
02165
02166
02167 for (a = activeVar; a < variables; a++) gradient(a) = linear(a);
02168 for (i = 0; i < variables; i++)
02169 {
02170 v = alpha(i);
02171 if (v == 0.0) continue;
02172
02173 unsigned int ei = variable[i].example;
02174 unsigned int vi = variable[i].label;
02175 unsigned int yi = example[ei].label;
02176 q = kernelMatrix.Row(ei, 0, examples, true);
02177 for (a = activeVar; a < variables; a++)
02178 {
02179 unsigned int ea = variable[a].example;
02180 unsigned int va = variable[a].label;
02181 unsigned int ya = example[ea].label;
02182
02183 double km = Modifier(vi, va, yi, ya);
02184 double k = q[ea];
02185 gradient(a) -= km * k * v;
02186 }
02187 }
02188
02189 for (i = 0; i < examples; i++) example[i].active = classes;
02190 activeEx = examples;
02191 activeVar = variables;
02192
02193 if (! complete) Shrink();
02194 }
02195
02196 void QpBoxAllInOneDecomp::DeactivateVariable(unsigned int v)
02197 {
02198 unsigned int ev = variable[v].example;
02199 unsigned int iv = variable[v].index;
02200 tExample* exv = &example[ev];
02201 unsigned int ih = exv->active - 1;
02202 unsigned int h = exv->variables[ih];
02203 variable[v].index = ih;
02204 variable[h].index = iv;
02205 std::swap(exv->variables[iv], exv->variables[ih]);
02206 iv = ih;
02207 exv->active--;
02208
02209 unsigned int j = activeVar - 1;
02210 unsigned int ej = variable[j].example;
02211 unsigned int ij = variable[j].index;
02212 tExample* exj = &example[ej];
02213
02214
02215 XCHG_A(double, boxMin, v, j);
02216 XCHG_A(double, boxMax, v, j);
02217 XCHG_A(double, linear, v, j);
02218 XCHG_A(double, alpha, v, j);
02219 XCHG_A(double, gradient, v, j);
02220 XCHG_V(tVariable, variable, v, j);
02221
02222 std::swap(exv->variables[iv], exj->variables[ij]);
02223
02224 activeVar--;
02225 }
02226
02227 void QpBoxAllInOneDecomp::DeactivateExample(unsigned int e)
02228 {
02229 unsigned int j = activeEx - 1;
02230
02231 XCHG_A(double, diagonal, e, j);
02232 XCHG_V(tExample, example, e, j);
02233
02234 unsigned int v;
02235 unsigned int* pe = example[e].variables;
02236 unsigned int* pj = example[j].variables;
02237 for (v=0; v<classes; v++)
02238 {
02239 variable[pe[v]].example = e;
02240 variable[pj[v]].example = j;
02241 }
02242
02243
02244 kernelMatrix.CacheRowRelease(e);
02245 kernelMatrix.FlipColumnsAndRows(e, j);
02246
02247 activeEx--;
02248 }
02249
02250
02252
02253
02254 QpCrammerSingerDecomp::QpCrammerSingerDecomp(CachedMatrix& kernel, const Array<double>& y, unsigned int classes)
02255 : kernelMatrix(kernel)
02256 {
02257 SIZE_CHECK(y.ndim() == 2);
02258
02259 examples = kernelMatrix.getMatrixSize();
02260 this->classes = classes;
02261 variables = examples * classes;
02262
02263 SIZE_CHECK(y.dim(0) == examples);
02264 SIZE_CHECK(y.dim(1) == 1);
02265
02266
02267 alpha.resize(variables, false);
02268 diagonal.resize(examples, false);
02269 gradient.resize(variables, false);
02270 linear.resize(variables, false);
02271 boxMin.resize(variables, false);
02272 boxMax.resize(variables, false);
02273 example.resize(examples);
02274 variable.resize(variables);
02275 storage.resize(variables);
02276
02277
02278 unsigned int i;
02279 for (i = 0; i < examples; i++)
02280 {
02281 diagonal(i) = kernelMatrix.Entry(i, i);
02282 example[i].index = i;
02283 example[i].label = (unsigned int)y(i, 0);
02284 example[i].active = classes;
02285 example[i].variables = &storage[classes * i];
02286 }
02287 for (i = 0; i < variables; i++)
02288 {
02289 variable[i].example = i / classes;
02290 variable[i].index = i % classes;
02291 variable[i].label = i % classes;
02292 storage[i] = i;
02293 }
02294
02295 maxIter = -1;
02296 }
02297
02298 QpCrammerSingerDecomp::~QpCrammerSingerDecomp()
02299 {
02300 }
02301
02302
02303 void QpCrammerSingerDecomp::Solve(Array<double>& solutionVector,
02304 double beta,
02305 double eps)
02306 {
02307 unsigned int a, b, bc, i, j = 0;
02308 float* q = NULL;
02309
02310
02311 for (a = 0; a < examples; a++)
02312 {
02313 unsigned int y = example[a].label;
02314 for (b = 0; b < classes; b++)
02315 {
02316 j = example[a].variables[b];
02317 alpha(j) = solutionVector(j);
02318 unsigned int v = variable[j].label;
02319 if (y == v)
02320 {
02321 linear(j) = beta;
02322 boxMin(j) = -1e100;
02323 boxMax(j) = 1.0;
02324 }
02325 else
02326 {
02327 linear(j) = 0.0;
02328 boxMin(j) = -1e100;
02329 boxMax(j) = 0.0;
02330 }
02331 }
02332 }
02333
02334 epsilon = eps;
02335
02336 activeEx = examples;
02337 activeVar = variables;
02338
02339
02340 gradient = linear;
02341 unsigned int e = 0xffffffff;
02342 for (a=0; a<activeEx; a++)
02343 {
02344 tExample* ex = &example[a];
02345 bc = ex->active;
02346 for (b = 0; b < bc; b++)
02347 {
02348 j = ex->variables[b];
02349 double v = alpha(j);
02350 if (v != 0.0)
02351 {
02352 unsigned int h;
02353 unsigned int vj = variable[j].label;
02354 if (e != a)
02355 {
02356 q = kernelMatrix.Row(a, 0, activeEx);
02357 e = a;
02358 }
02359 for (h=0; h<activeVar; h++)
02360 {
02361 unsigned int vh = variable[h].label;
02362 if (vh == vj)
02363 {
02364 unsigned int eh = variable[h].example;
02365 gradient(h) -= v * q[eh];
02366 }
02367 }
02368 }
02369 }
02370 }
02371
02372
02373 Shrink();
02374
02375 bUnshrinked = false;
02376 unsigned int shrinkCounter = (activeVar < 1000) ? activeVar : 1000;
02377
02378
02379 iter = 0;
02380 optimal = false;
02381 while (iter != maxIter)
02382 {
02383
02384 if (SelectWorkingSet(i, j) <= epsilon)
02385 {
02386
02387
02388
02389 Unshrink(true);
02390
02391
02392 if (SelectWorkingSet(i, j) <= epsilon)
02393 {
02394 optimal = true;
02395 break;
02396 }
02397
02398
02399 Shrink();
02400 shrinkCounter = (activeVar < 1000) ? activeVar : 1000;
02401 }
02402
02403
02404 {
02405
02406 unsigned int e = variable[i].example;
02407
02408 double ai = alpha(i);
02409 double Li = boxMin(i);
02410 double Ui = boxMax(i);
02411 double aj = alpha(j);
02412 double Lj = boxMin(j);
02413 double Uj = boxMax(j);
02414
02415 unsigned int vi = variable[i].label;
02416 unsigned int vj = variable[j].label;
02417
02418
02419 q = kernelMatrix.Row(e, 0, activeEx);
02420
02421
02422 double nominator = gradient(i) - gradient(j);
02423 double denominator = 2.0 * diagonal(e);
02424 double mu = nominator / denominator;
02425 if (ai + mu < Li) mu = Li - ai;
02426 else if (ai + mu > Ui) mu = Ui - ai;
02427 if (aj - mu < Lj) mu = aj - Lj;
02428 else if (aj - mu > Uj) mu = aj - Uj;
02429 alpha(i) += mu;
02430 alpha(j) -= mu;
02431
02432
02433 for (a = 0; a < activeEx; a++)
02434 {
02435 double k = q[a];
02436 tExample* ex = &example[a];
02437 unsigned int b, bc = ex->active;
02438 for (b = 0; b < bc; b++)
02439 {
02440 unsigned int h = ex->variables[b];
02441 unsigned int vh = variable[h].label;
02442 if (vh == vi) gradient(h) -= mu * k;
02443 else if (vh == vj) gradient(h) += mu * k;
02444 }
02445 }
02446 }
02447
02448 shrinkCounter--;
02449 if (shrinkCounter == 0)
02450 {
02451
02452 Shrink();
02453
02454 shrinkCounter = (activeVar < 1000) ? activeVar : 1000;
02455 }
02456
02457 iter++;
02458 }
02459
02460
02461 for (i = 0; i < variables; i++)
02462 {
02463 unsigned int j = classes * example[variable[i].example].index + variable[i].label;
02464 solutionVector(j) = alpha(i);
02465 }
02466 }
02467
02468
02469
02470 double QpCrammerSingerDecomp::SelectWorkingSet(unsigned int& i, unsigned int& j)
02471 {
02472 double largest = 0.0;
02473
02474 unsigned int a, b, bc, w;
02475 for (a=0; a<activeEx; a++)
02476 {
02477 tExample* ex = &example[a];
02478 bc = ex->active;
02479 double m = 1e100;
02480 double M = -1e100;
02481 unsigned int n = 0, N = 1;
02482 for (b=0; b<bc; b++)
02483 {
02484 w = ex->variables[b];
02485 double v = alpha(w);
02486 double g = gradient(w);
02487 if (v < boxMax(w))
02488 {
02489 if (g > M)
02490 {
02491 M = g;
02492 N = w;
02493 }
02494 }
02495 if (v > boxMin(w))
02496 {
02497 if (g < m)
02498 {
02499 m = g;
02500 n = w;
02501 }
02502 }
02503 }
02504 if (M - m > largest)
02505 {
02506 largest = M - m;
02507 i = N;
02508 j = n;
02509 }
02510 }
02511
02512 return largest;
02513 }
02514
02515 void QpCrammerSingerDecomp::Shrink()
02516 {
02517 if (! bUnshrinked)
02518 {
02519 unsigned int i, j;
02520 double violation = SelectWorkingSet(i, j);
02521 if (violation < 10.0 * epsilon)
02522 {
02523
02524 Unshrink(true);
02525 bUnshrinked = true;
02526 }
02527 }
02528
02529
02530 bool se = false;
02531 int a;
02532 for (a = activeEx-1; a >= 0; a--)
02533 {
02534
02535 tExample* ex = &example[a];
02536 unsigned int b, bc = ex->active;
02537 double m = 1e100;
02538 double M = -1e100;
02539 for (b=0; b<bc; b++)
02540 {
02541 unsigned int w = ex->variables[b];
02542 double v = alpha(w);
02543 double g = gradient(w);
02544 if (v < boxMax(w))
02545 {
02546 if (g > M)
02547 {
02548 M = g;
02549 }
02550 }
02551 if (v > boxMin(w))
02552 {
02553 if (g < m)
02554 {
02555 m = g;
02556 }
02557 }
02558 }
02559 for (b=0; b<bc; b++)
02560 {
02561 unsigned int w = ex->variables[b];
02562 double v = alpha(w);
02563 double g = gradient(w);
02564 if (v == boxMin(w) && g < m)
02565 {
02566 DeactivateVariable(w);
02567 b--;
02568 bc--;
02569 }
02570 else if (v == boxMax(w) && g > M)
02571 {
02572 DeactivateVariable(w);
02573 b--;
02574 bc--;
02575 }
02576 }
02577 if (bc == 0)
02578 {
02579 DeactivateExample(a);
02580 se = true;
02581 }
02582 }
02583
02584 if (se)
02585 {
02586
02587 for (a = 0; a < (int)activeEx; a++)
02588 {
02589 if (kernelMatrix.getCacheRowSize(a) > activeEx) kernelMatrix.CacheRowResize(a, activeEx);
02590 }
02591 }
02592 }
02593
02594 void QpCrammerSingerDecomp::Unshrink(bool complete)
02595 {
02596 if (activeVar == variables) return;
02597
02598 unsigned int i, a;
02599 float* q;
02600 double v;
02601
02602
02603 for (a = activeVar; a < variables; a++) gradient(a) = linear(a);
02604 for (i = 0; i < variables; i++)
02605 {
02606 v = alpha(i);
02607 if (v == 0.0) continue;
02608
02609 unsigned int ei = variable[i].example;
02610 unsigned int vi = variable[i].label;
02611 q = kernelMatrix.Row(ei, 0, examples, true);
02612 for (a = activeVar; a < variables; a++)
02613 {
02614 if (variable[a].label == vi)
02615 {
02616 unsigned int ea = variable[a].example;
02617 gradient(a) -= q[ea] * v;
02618 }
02619 }
02620 }
02621
02622 for (i = 0; i < examples; i++) example[i].active = classes;
02623 activeEx = examples;
02624 activeVar = variables;
02625
02626 if (! complete) Shrink();
02627 }
02628
02629 void QpCrammerSingerDecomp::DeactivateVariable(unsigned int v)
02630 {
02631 unsigned int ev = variable[v].example;
02632 unsigned int iv = variable[v].index;
02633 tExample* exv = &example[ev];
02634 unsigned int ih = exv->active - 1;
02635 unsigned int h = exv->variables[ih];
02636 variable[v].index = ih;
02637 variable[h].index = iv;
02638 std::swap(exv->variables[iv], exv->variables[ih]);
02639 iv = ih;
02640 exv->active--;
02641
02642 unsigned int j = activeVar - 1;
02643 unsigned int ej = variable[j].example;
02644 unsigned int ij = variable[j].index;
02645 tExample* exj = &example[ej];
02646
02647
02648 XCHG_A(double, boxMin, v, j);
02649 XCHG_A(double, boxMax, v, j);
02650 XCHG_A(double, linear, v, j);
02651 XCHG_A(double, alpha, v, j);
02652 XCHG_A(double, gradient, v, j);
02653 XCHG_V(tVariable, variable, v, j);
02654
02655 std::swap(exv->variables[iv], exj->variables[ij]);
02656
02657 activeVar--;
02658 }
02659
02660 void QpCrammerSingerDecomp::DeactivateExample(unsigned int e)
02661 {
02662 unsigned int j = activeEx - 1;
02663
02664 XCHG_A(double, diagonal, e, j);
02665 XCHG_V(tExample, example, e, j);
02666
02667 unsigned int v;
02668 unsigned int* pe = example[e].variables;
02669 unsigned int* pj = example[j].variables;
02670 for (v=0; v<classes; v++)
02671 {
02672 variable[pe[v]].example = e;
02673 variable[pj[v]].example = j;
02674 }
02675
02676
02677 kernelMatrix.CacheRowRelease(e);
02678 kernelMatrix.FlipColumnsAndRows(e, j);
02679
02680 activeEx--;
02681 }
02682
02683
02685
02686
02687 void QpBoxAndEqCG::Solve(const Array<double>& quadratic,
02688 const Array<double>& linear,
02689 const Array<double>& boxMin,
02690 const Array<double>& boxMax,
02691 const Array<double>& eqMat,
02692 Array<double>& point,
02693 double accuracy)
02694 {
02695 SIZE_CHECK(quadratic.ndim() == 2);
02696 SIZE_CHECK(linear.ndim() == 1);
02697 SIZE_CHECK(boxMin.ndim() == 1);
02698 SIZE_CHECK(boxMax.ndim() == 1);
02699 SIZE_CHECK(eqMat.ndim() == 2);
02700 SIZE_CHECK(point.ndim() == 1);
02701
02702 int dimension = quadratic.dim(0);
02703 int equations = eqMat.dim(0);
02704
02705 SIZE_CHECK((int)quadratic.dim(1) == dimension);
02706 SIZE_CHECK((int)linear.dim(0) == dimension);
02707 SIZE_CHECK((int)boxMin.dim(0) == dimension);
02708 SIZE_CHECK((int)boxMax.dim(0) == dimension);
02709 SIZE_CHECK((int)eqMat.dim(1) == dimension);
02710 SIZE_CHECK((int)point.dim(0) == dimension);
02711
02712 int i, j;
02713 Array<double> direction(dimension);
02714 Array<bool> active(dimension);
02715 Array<double> gradient(dimension);
02716 Array<double> conjugate(dimension);
02717 Array<double> equality(eqMat);
02718 conjugate = 0.0;
02719 double DirLen2 = 0.0;
02720 double DirLen2old = 0.0;
02721 double accuracy2 = accuracy * accuracy;
02722 bool changed, bounds_changed;
02723 int nActive = 0;
02724 int nUpdatesLeft = -1;
02725 int bound = -1;
02726 int nReset = 0;
02727 double step = 0.0;
02728 double clipped = 0.0;
02729 double value;
02730 double first = 0.0;
02731 double second = 0.0;
02732 double norm2;
02733
02734 active = false;
02735
02736 int iter, maxiter = 10 * dimension * dimension;
02737 for (iter=0; iter<maxiter; iter++)
02738 {
02739 if (nUpdatesLeft == -1)
02740 {
02741
02742 for (i=0; i<dimension; i++)
02743 {
02744 value = linear(i);
02745 for (j=0; j<dimension; j++) value += quadratic(i, j) * point(j);
02746 gradient(i) = value;
02747 }
02748 nUpdatesLeft = 100;
02749 }
02750
02751
02752 bounds_changed = false;
02753 do
02754 {
02755 changed = false;
02756 for (i=0; i<dimension; i++)
02757 {
02758 if (active(i))
02759 {
02760 equality = eqMat;
02761 active(i) = false;
02762 Project(active, equality, gradient, direction);
02763 double g = direction(i);
02764 if ((g <= 0.0 && point(i) == boxMin(i))
02765 || (g >= 0.0 && point(i) == boxMax(i)))
02766 {
02767 nActive--;
02768 changed = true;
02769 }
02770 else active(i) = true;
02771 }
02772 else
02773 {
02774 equality = eqMat;
02775 active(i) = true;
02776 Project(active, equality, gradient, direction);
02777 double g = direction(i);
02778 if ((g > 0.0 && point(i) == boxMin(i))
02779 || (g < 0.0 && point(i) == boxMax(i)))
02780 {
02781 nActive++;
02782 changed = true;
02783 }
02784 else active(i) = false;
02785 }
02786 }
02787 bounds_changed = bounds_changed || changed;
02788 }
02789 while (changed);
02790 if (bounds_changed && iter > 0) nReset = 0;
02791
02792
02793 if (nActive + 1 >= dimension) break;
02794
02795
02796
02797 equality = eqMat;
02798 Project(active, equality, gradient, direction);
02799
02800
02801 DirLen2old = DirLen2;
02802 DirLen2 = 0.0;
02803 for (i=0; i<dimension; i++)
02804 {
02805 if (active(i)) continue;
02806 value = direction(i);
02807 DirLen2 += value * value;
02808 }
02809
02810
02811 nReset--;
02812 if (nReset == 0)
02813 {
02814
02815
02816
02817 break;
02818 }
02819 else if (nReset < 0)
02820 {
02821
02822 conjugate = direction;
02823 nReset = dimension - equations - nActive;
02824 }
02825 else
02826 {
02827 double beta = DirLen2 / DirLen2old;
02828 for (i=0; i<dimension; i++)
02829 {
02830 if (active(i)) continue;
02831 else conjugate(i) = direction(i) + beta * conjugate(i);
02832 }
02833 }
02834
02835
02836 first = 0.0;
02837 second = 0.0;
02838 norm2 = 0.0;
02839 for (i=0; i<dimension; i++)
02840 {
02841 if (active(i)) continue;
02842 double c = conjugate(i);
02843 double Qc = 0.0;
02844 for (j=0; j<dimension; j++)
02845 {
02846 if (active(j)) continue;
02847 Qc += quadratic(i, j) * conjugate(j);
02848 }
02849 first += gradient(i) * c;
02850 second += c * Qc;
02851 norm2 += c * c;
02852 }
02853 if (second <= 0.0) break;
02854 step = -first / second;
02855
02856
02857 if (nReset <= 1 && step * step * norm2 < accuracy2) break;
02858
02859
02860 bound = -1;
02861 clipped = step;
02862 for (i=0; i<dimension; i++)
02863 {
02864 if (active(i)) continue;
02865 if (point(i) + clipped * conjugate(i) > boxMax(i))
02866 {
02867 clipped = (boxMax(i) - point(i)) / conjugate(i);
02868 bound = i;
02869 }
02870 else if (point(i) + clipped * conjugate(i) < boxMin(i))
02871 {
02872 clipped = (boxMin(i) - point(i)) / conjugate(i);
02873 bound = i;
02874 }
02875 }
02876
02877
02878 if (5 * nActive > dimension && nUpdatesLeft > 0)
02879 {
02880
02881 for (i=0; i<dimension; i++)
02882 {
02883 if (active(i)) continue;
02884 double delta = clipped * conjugate(i);
02885 for (j=0; j<dimension; j++) gradient(j) += quadratic(i, j) * delta;
02886 }
02887 nUpdatesLeft--;
02888 }
02889 else nUpdatesLeft = -1;
02890
02891
02892 changed = false;
02893 for (i=0; i<dimension; i++)
02894 {
02895 if (active(i)) continue;
02896 double p = point(i);
02897 double newp = p + clipped * conjugate(i);
02898 point(i) = newp;
02899 if (p != newp) changed = true;
02900 }
02901
02902
02903 if (! changed) break;
02904
02905
02906 if (bound != -1)
02907 {
02908
02909
02910 double threshold = 0.5 * (boxMax(bound) + boxMin(bound));
02911 if (point(bound) > threshold) point(bound) = boxMax(bound);
02912 else point(bound) = boxMin(bound);
02913 nReset = 0;
02914 }
02915 }
02916
02917 if (iter >= maxiter)
02918 {
02919 throw SHARKEXCEPTION("QpBoxAndEqCG did not converge");
02920 printf("\n\n***************** QpBoxAndEqCG did not converge!!!\n\n");
02921 printf("boxMin:\n");
02922 writeArray(boxMin, std::cout);
02923 printf("boxMax:\n");
02924 writeArray(boxMax, std::cout);
02925 printf("point:\n");
02926 writeArray(point, std::cout);
02927 printf("gradient:\n");
02928 writeArray(gradient, std::cout);
02929 printf("direction:\n");
02930 writeArray(direction, std::cout);
02931 printf("conjugate:\n");
02932 writeArray(conjugate, std::cout);
02933 printf("active:\n");
02934 writeArray(active, std::cout);
02935 }
02936 }
02937
02938 void QpBoxAndEqCG::Orthogonalize(int oc, const Array<double>& ortho, const Array<bool>& active, ArrayReference<double> vec)
02939 {
02940 int o, d, dim = ortho.dim(1);
02941 double scp, norm;
02942
02943
02944 for (o=0; o<oc; o++)
02945 {
02946 scp = 0.0;
02947 for (d=0; d<dim; d++)
02948 {
02949 if (active(d)) continue;
02950 scp += ortho(o, d) * vec(d);
02951 }
02952 for (d=0; d<dim; d++)
02953 {
02954 if (active(d)) vec(d) = 0.0;
02955 else vec(d) -= scp * ortho(o, d);
02956 }
02957 }
02958
02959
02960 scp = 0.0;
02961 for (d=0; d<dim; d++)
02962 {
02963 if (active(d)) continue;
02964 scp += vec(d) * vec(d);
02965 }
02966 norm = sqrt(scp);
02967 for (d=0; d<dim; d++)
02968 {
02969 if (active(d)) continue;
02970 vec(d) /= norm;
02971 }
02972 }
02973
02974 void QpBoxAndEqCG::Orthogonalize(Array<double>& eq, const Array<bool>& active)
02975 {
02976 int e, ec = eq.dim(0);
02977 for (e=0; e<ec; e++)
02978 {
02979 Orthogonalize(e, eq, active, eq[e]);
02980 }
02981 }
02982
02983 void QpBoxAndEqCG::Project(const Array<bool>& active, Array<double>& eq, const Array<double>& gradient, Array<double>& direction)
02984 {
02985 Orthogonalize(eq, active);
02986
02987 int o, oc = eq.dim(0);
02988 int d, dim = eq.dim(1);
02989 double scp;
02990 for (o=0; o<oc; o++)
02991 {
02992 scp = 0.0;
02993 for (d=0; d<dim; d++)
02994 {
02995 if (active(d)) continue;
02996 scp += eq(o, d) * gradient(d);
02997 }
02998 for (d=0; d<dim; d++)
02999 {
03000 if (active(d)) direction(d) = 0.0;
03001 else direction(d) = gradient(d) - scp * eq(o, d);
03002 }
03003 }
03004 }
03005
03006
03008
03009
03010 void QpBoxAndEqDecomp::Solve(const Array<double>& quadratic,
03011 const Array<double>& linear,
03012 const Array<double>& boxMin,
03013 const Array<double>& boxMax,
03014 const Array<double>& eqMat,
03015 Array<double>& point,
03016 double accuracy)
03017 {
03018 SIZE_CHECK(quadratic.ndim() == 2);
03019 SIZE_CHECK(linear.ndim() == 1);
03020 SIZE_CHECK(boxMin.ndim() == 1);
03021 SIZE_CHECK(boxMax.ndim() == 1);
03022 SIZE_CHECK(eqMat.ndim() == 2);
03023 SIZE_CHECK(point.ndim() == 1);
03024
03025 int dimension = quadratic.dim(0);
03026 int equations = eqMat.dim(0);
03027
03028 SIZE_CHECK((int)quadratic.dim(1) == dimension);
03029 SIZE_CHECK((int)linear.dim(0) == dimension);
03030 SIZE_CHECK((int)boxMin.dim(0) == dimension);
03031 SIZE_CHECK((int)boxMax.dim(0) == dimension);
03032 SIZE_CHECK((int)eqMat.dim(1) == dimension);
03033 SIZE_CHECK((int)point.dim(0) == dimension);
03034
03035 Array<double> eq(eqMat);
03036 Orthogonalize(eq);
03037
03038 Array<double> gradient(linear);
03039 Array<double> direction(dimension);
03040 int workingsize = 2 * equations + 1;
03041 int i, j, k;
03042
03043 Array<int> workingset(workingsize);
03044 Array<double> subQ(workingsize, workingsize);
03045 Array<double> subL(workingsize);
03046 Array<double> subBoxMin(workingsize);
03047 Array<double> subBoxMax(workingsize);
03048 Array<double> subEqMat(equations, workingsize);
03049 Array<double> subPoint(workingsize);
03050
03051
03052 for (i=0; i<dimension; i++)
03053 {
03054 double p = point(i);
03055 if (p != 0.0)
03056 {
03057 for (j=0; j<dimension; j++) gradient(j) += p * quadratic(i, j);
03058 }
03059 }
03060
03061
03062 while (true)
03063 {
03064
03065 double gNorm1 = 0.0;
03066 {
03067
03068 Project(eq, gradient, direction);
03069
03070
03071 for (i=0; i<workingsize; i++)
03072 {
03073 int best = 0;
03074 double bestG = 0.0;
03075 for (j=0; j<dimension; j++)
03076 {
03077 double d = direction(j);
03078 if (point(j) == boxMin(j) && d >= 0.0) continue;
03079 if (point(j) == boxMax(j) && d <= 0.0) continue;
03080 d = fabs(d);
03081 if (d > bestG)
03082 {
03083 for (k=0; k<i; k++) if (workingset(k) == j) break;
03084 if (k == i)
03085 {
03086 bestG = d;
03087 best = j;
03088 }
03089 }
03090 }
03091 workingset(i) = best;
03092 gNorm1 += bestG;
03093 }
03094 }
03095
03096
03097 if (gNorm1 < accuracy) break;
03098
03099
03100 for (i=0; i<workingsize; i++)
03101 {
03102 j = workingset(i);
03103 for (k=0; k<workingsize; k++) subQ(i, k) = quadratic(j, workingset(k));
03104 subL(i) = linear(j);
03105 subBoxMin(i) = boxMin(j);
03106 subBoxMax(i) = boxMax(j);
03107 for (k=0; k<equations; k++) subEqMat(k, i) = eqMat(k, j);
03108 subPoint(i) = point(j);
03109 }
03110 QpBoxAndEqCG::Solve(subQ, subL, subBoxMin, subBoxMax, subEqMat, subPoint);
03111
03112
03113 for (i=0; i<workingsize; i++)
03114 {
03115 j = workingset(i);
03116 double delta = subPoint(i) - point(j);
03117 if (delta == 0.0) continue;
03118 for (k=0; k<dimension; k++) gradient(k) += delta * quadratic(j, k);
03119 point(j) = subPoint(i);
03120 }
03121 }
03122 }
03123
03124 void QpBoxAndEqDecomp::Orthogonalize(Array<double>& eq)
03125 {
03126 int e, ec = eq.dim(0);
03127 int o, d, dim = eq.dim(1);
03128 double scp, norm;
03129 for (e=0; e<ec; e++)
03130 {
03131
03132 for (o=0; o<e; o++)
03133 {
03134 scp = 0.0;
03135 for (d=0; d<dim; d++)
03136 {
03137 scp += eq(o, d) * eq(e, d);
03138 }
03139 for (d=0; d<dim; d++)
03140 {
03141 eq(e, d) -= scp * eq(o, d);
03142 }
03143 }
03144
03145
03146 scp = 0.0;
03147 for (d=0; d<dim; d++)
03148 {
03149 scp += eq(e, d) * eq(e, d);
03150 }
03151 norm = sqrt(scp);
03152 for (d=0; d<dim; d++)
03153 {
03154 eq(e, d) /= norm;
03155 }
03156 }
03157 }
03158
03159 void QpBoxAndEqDecomp::Project(const Array<double>& eq, const Array<double>& gradient, Array<double>& direction)
03160 {
03161 int o, oc = eq.dim(0);
03162 int d, dim = eq.dim(1);
03163 double scp;
03164 for (o=0; o<oc; o++)
03165 {
03166 scp = 0.0;
03167 for (d=0; d<dim; d++)
03168 {
03169 scp += eq(o, d) * gradient(d);
03170 }
03171 for (d=0; d<dim; d++)
03172 {
03173 direction(d) = gradient(d) - scp * eq(o, d);
03174 }
03175 }
03176 }
03177
03178
03180
03181
03182
03183
03184
03185
03186
03187
03188
03189
03190
03191
03192
03193
03194
03195
03196
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206
03207
03208
03209
03210
03211
03212
03213
03214
03215
03216
03217
03218
03219
03220
03221
03222
03223
03224
03225
03226
03227
03228
03229
03230
03231
03232
03233
03234
03235
03236
03237
03238
03239
03240
03241
03242
03243
03244
03245
03246
03247
03248
03249
03250
03251
03252
03253
03254
03255
03256
03257
03258
03259
03260
03261
03262
03263
03264
03265
03266
03267
03268
03269
03270
03271
03272
03273
03274
03275
03276
03277
03278
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294
03295
03296
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325
03326
03327
03328
03329
03330
03331
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346
03347
03348
03349
03350
03351
03352
03353
03354
03355
03356
03357
03358
03359
03360
03361
03362
03363
03364
03365
03366
03367
03368
03369
03370
03371
03372
03373
03374
03375
03376
03377
03378
03379
03380
03381
03382
03383
03384
03385
03386
03387
03388
03389
03390
03391
03392
03393
03394
03395
03396
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406
03407
03408
03409
03410
03411
03412
03413
03414
03415
03416
03417
03418
03419
03420
03421
03422
03423
03424
03425
03426
03427
03428
03429
03430
03431
03432
03433
03434
03435
03436
03437
03438
03439
03440
03441
03442
03443
03444
03445
03446
03447
03448
03449
03450
03451
03452
03453
03454
03455
03456
03457
03458
03459
03460
03461
03462
03463
03464
03465
03466
03467
03468
03469
03470
03471
03472
03473
03474
03475
03476
03477
03478
03479
03480
03481
03482
03483
03484
03485
03486
03487
03488
03489
03490
03491
03492
03493
03494
03495
03496
03497
03498
03499
03500
03501
03502
03503
03504
03505
03506
03507
03508
03509
03510
03511
03512
03513
03514
03515
03516
03517
03518
03519
03520
03521
03522
03523
03524
03525
03526
03527
03528
03529
03530
03531
03532
03533
03534
03535
03536
03537
03538
03539
03540
03541
03542
03543
03544
03545
03546
03547
03548
03549
03550
03551
03552
03553
03554
03555
03556
03557
03558
03559
03560
03561
03562
03563
03564
03565
03566
03567
03568
03569
03570
03571
03572
03573