00001
00041
00042
00043
00044 #include <SharkDefs.h>
00045 #include <ReClaM/KernelFunction.h>
00046 #include <math.h>
00047
00048
00050
00051
00052 KernelFunction::KernelFunction()
00053 {
00054 }
00055
00056 KernelFunction::~KernelFunction()
00057 {
00058 }
00059
00060
00061 double KernelFunction::evalDerivative(const Array<double>& x1, const Array<double>& x2, Array<double>& derivative) const
00062 {
00063 SIZE_CHECK(x1.ndim() == 1);
00064 SIZE_CHECK(x2.ndim() == 1);
00065 SIZE_CHECK(x1.nelem() == x2.nelem());
00066 KernelFunction* pT = const_cast<KernelFunction*>(this);
00067
00068 int i, ic = getParameterDimension();
00069 double temp;
00070 double ret = eval(x1, x2);
00071 derivative.resize(ic, false);
00072 for (i = 0; i < ic; i++)
00073 {
00074 temp = getParameter(i);
00075 pT->setParameter(i, temp + epsilon);
00076 derivative(i) = (eval(x1, x2) - ret) / epsilon;
00077 pT->setParameter(i, temp);
00078 }
00079 return ret;
00080 }
00081
00082 void KernelFunction::model(const Array<double>& input, Array<double> &output)
00083 {
00084 output.resize(1, false);
00085 output(0) = eval(input[0], input[1]);
00086 }
00087
00088 void KernelFunction::modelDerivative(const Array<double>& input, Array<double>& derivative)
00089 {
00090 evalDerivative(input[0], input[1], derivative);
00091 }
00092
00093 void KernelFunction::modelDerivative(const Array<double>& input, Array<double> &output, Array<double>& derivative)
00094 {
00095 output.resize(1, false);
00096 output(0) = evalDerivative(input[0], input[1], derivative);
00097 }
00098
00099
00101
00102
00103 LinearKernel::LinearKernel()
00104 {
00105 parameter.resize(0, false);
00106 }
00107
00108 LinearKernel::~LinearKernel()
00109 {
00110 }
00111
00112
00113 double LinearKernel::eval(const Array<double>& x1, const Array<double>& x2) const
00114 {
00115 unsigned int i, ic = x1.nelem();
00116 SIZE_CHECK(x1.ndim() == 1);
00117 SIZE_CHECK(x2.ndim() == 1);
00118 SIZE_CHECK(x2.nelem() == ic);
00119
00120 double ret = 0.0;
00121 for (i = 0; i < ic; i++) ret += x1(i) * x2(i);
00122 return ret;
00123 }
00124
00125 double LinearKernel::evalDerivative(const Array<double>& x1, const Array<double>& x2, Array<double>& derivative) const
00126 {
00127 derivative.resize(0, false);
00128 return eval(x1, x2);
00129 }
00130
00131
00133
00134
00135 PolynomialKernel::PolynomialKernel(int degree, double offset)
00136 {
00137 parameter.resize(2, false);
00138 parameter(0) = degree;
00139 parameter(1) = offset;
00140 }
00141
00142 PolynomialKernel::~PolynomialKernel()
00143 {
00144 }
00145
00146
00147 double PolynomialKernel::eval(const Array<double>& x1, const Array<double>& x2) const
00148 {
00149 unsigned int i, ic = x1.nelem();
00150 SIZE_CHECK(x1.ndim() == 1);
00151 SIZE_CHECK(x2.ndim() == 1);
00152 SIZE_CHECK(x2.nelem() == ic);
00153
00154 double dot = 0.0;
00155 for (i = 0; i < ic; i++) dot += x1(i) * x2(i);
00156 return pow(dot + parameter(1), parameter(0));
00157 }
00158
00159 void PolynomialKernel::setParameter(unsigned int index, double value)
00160 {
00161 if (index == 0)
00162 {
00163 parameter(0) = (int)value;
00164 if (parameter(0) < 1.0) throw SHARKEXCEPTION("[PolynomialKernel::setParameter] invalid degree");
00165 }
00166 else if (index == 1)
00167 {
00168 parameter(1) = value;
00169 }
00170 else throw SHARKEXCEPTION("[PolynomialKernel::setParameter] invalid parameter index");
00171 }
00172
00173 bool PolynomialKernel::isFeasible()
00174 {
00175 return (parameter(0) > 0.0 && (int)parameter(0) == parameter(0));
00176 }
00177
00178
00180
00181
00182 RBFKernel::RBFKernel(double gamma)
00183 {
00184 parameter.resize(1, false);
00185 parameter(0) = gamma;
00186 }
00187
00188 RBFKernel::~RBFKernel()
00189 {
00190 }
00191
00192
00193 double RBFKernel::eval(const Array<double>& x1, const Array<double>& x2) const
00194 {
00195 unsigned int i, ic = x1.nelem();
00196 SIZE_CHECK(x1.ndim() == 1);
00197 SIZE_CHECK(x2.ndim() == 1);
00198 SIZE_CHECK(x2.nelem() == ic);
00199
00200 double tmp, dist2 = 0.0;
00201 for (i = 0; i < ic; i++)
00202 {
00203 tmp = x1(i) - x2(i);
00204 dist2 += tmp * tmp;
00205 }
00206 return exp(-parameter(0) * dist2);
00207 }
00208
00209 double RBFKernel::evalDerivative(const Array<double>& x1, const Array<double>& x2, Array<double>& derivative) const
00210 {
00211 unsigned int i, ic = x1.nelem();
00212 SIZE_CHECK(x1.ndim() == 1);
00213 SIZE_CHECK(x2.ndim() == 1);
00214 SIZE_CHECK(x2.nelem() == ic);
00215
00216 derivative.resize(1, false);
00217 double tmp, dist2 = 0.0;
00218 for (i = 0; i < ic; i++)
00219 {
00220 tmp = x1(i) - x2(i);
00221 dist2 += tmp * tmp;
00222 }
00223 double ret = exp(-parameter(0) * dist2);
00224 derivative(0) = -dist2 * ret;
00225 return ret;
00226 }
00227
00228 bool RBFKernel::isFeasible()
00229 {
00230 return (parameter(0) > 0.0);
00231 }
00232
00233 double RBFKernel::getSigma()
00234 {
00235 return sqrt(.5 / getParameter(0));
00236 };
00237
00238 void RBFKernel::setSigma(double sigma)
00239 {
00240 setParameter(0, .5 / (sigma * sigma));
00241 }
00242
00243
00245
00246
00247 NormalizedRBFKernel::NormalizedRBFKernel()
00248 {
00249 parameter.resize(1, false);
00250 parameter = 1.;
00251 }
00252
00253 NormalizedRBFKernel::NormalizedRBFKernel(double s)
00254 {
00255 parameter.resize(1, false);
00256 parameter = s;
00257 }
00258
00259
00260 void NormalizedRBFKernel::setSigma(double s)
00261 {
00262 setParameter(0, s);
00263 }
00264
00265 double NormalizedRBFKernel::eval(const Array<double> &x, const Array<double> &z) const
00266 {
00267 double sum = 0;
00268 double sigma = parameter(0);
00269
00270 for (unsigned i = 0; i < x.dim(0); i++) sum += (x(i) - z(i)) * (x(i) - z(i));
00271 return exp(-sum / (2*sigma*sigma)) / (sigma * Sqrt2PI);
00272 }
00273
00274 double NormalizedRBFKernel::evalDerivative(const Array<double> &x, const Array<double> &z, Array<double>& derivative) const
00275 {
00276 double sum = 0;
00277 double sigma = parameter(0);
00278
00279 derivative.resize(1, false);
00280
00281 for (unsigned i = 0; i < x.dim(0); i++) sum += (x(i) - z(i)) * (x(i) - z(i));
00282 derivative(0) = (-exp(-sum / (2 * sigma * sigma)) + exp(-sum / (2 * sigma * sigma)) * sum / (sigma * sigma)) / (sigma * sigma * sqrt(2. * M_PI));
00283 return exp(-sum / (2*sigma*sigma)) / (sigma * Sqrt2PI);
00284 }
00285
00286
00288
00289
00290 NormalizedKernel::NormalizedKernel(KernelFunction* base)
00291 {
00292 baseKernel = base;
00293 int i, ic = baseKernel->getParameterDimension();
00294 parameter.resize(ic, false);
00295 for (i = 0; i < ic; i++) setParameter(i, baseKernel->getParameter(i));
00296 }
00297
00298 NormalizedKernel::~NormalizedKernel()
00299 {}
00300
00301
00302 void NormalizedKernel::setParameter(unsigned int index, double value)
00303 {
00304 parameter(index) = value;
00305 baseKernel->setParameter(index, value);
00306 }
00307
00308 double NormalizedKernel::eval(const Array<double>& x1, const Array<double>& x2) const
00309 {
00310 return baseKernel->eval(x1, x2) / sqrt(baseKernel->eval(x1, x1) * baseKernel->eval(x2, x2));
00311 }
00312
00313 double NormalizedKernel::evalDerivative(const Array<double>& x1, const Array<double>& x2, Array<double>& derivative) const
00314 {
00315 int i, ic = getParameterDimension();
00316 Array<double> der11(ic);
00317 Array<double> der12(ic);
00318 Array<double> der22(ic);
00319
00320
00321 double k11 = baseKernel->evalDerivative(x1, x1, der11);
00322 double k12 = baseKernel->evalDerivative(x1, x2, der12);
00323 double k22 = baseKernel->evalDerivative(x2, x2, der22);
00324 double s = sqrt(k11 * k22);
00325
00326
00327 derivative.resize(ic, false);
00328 for (i = 0; i < ic; i++)
00329 {
00330 derivative(i) = (der12(i) * k11 * k22 - 0.5 * k12 * (k11 * der22(i) + der11(i) * k22)) / (s * k11 * k22);
00331 }
00332
00333
00334 return k12 / s;
00335 }
00336
00337 bool NormalizedKernel::isFeasible()
00338 {
00339 return baseKernel->isFeasible();
00340 }
00341
00342
00344
00345
00346 WeightedSumKernel::WeightedSumKernel(const std::vector<KernelFunction*>& base)
00347 {
00348 int i, ic = base.size();
00349 if (ic == 0) throw SHARKEXCEPTION("[WeightedSumKernel] There must be at least one sub-kernel.");
00350 int j, jc;
00351 int p, pc = ic - 1;
00352 baseKernel.resize(ic);
00353 weight.resize(ic);
00354 for (i = 0; i < ic; i++)
00355 {
00356 pc += base[i]->getParameterDimension();
00357 baseKernel[i] = base[i];
00358 weight[i] = 1.0;
00359 }
00360 weightsum = ic;
00361 parameter.resize(pc, false);
00362
00363 p = 0;
00364 for (i = 0; i < ic - 1; i++)
00365 {
00366 parameter(p) = 0.0;
00367 p++;
00368 }
00369 for (i = 0; i < ic; i++)
00370 {
00371 jc = base[i]->getParameterDimension();
00372 for (j = 0; j < jc; j++)
00373 {
00374 parameter(p) = base[i]->getParameter(j);
00375 p++;
00376 }
00377 }
00378 }
00379
00380 WeightedSumKernel::~WeightedSumKernel()
00381 {
00382 }
00383
00384
00385 void WeightedSumKernel::setParameter(unsigned int index, double value)
00386 {
00387 parameter(index) = value;
00388
00389 unsigned int ic = baseKernel.size();
00390 if (index < ic - 1)
00391 {
00392
00393 unsigned int i;
00394 double a;
00395 weight[0] = 1.0;
00396 weightsum = 1.0;
00397 for (i = 0; i < ic - 1; i++)
00398 {
00399 a = exp(parameter(i));
00400 weight[i+1] = a;
00401 weightsum += a;
00402 }
00403 }
00404 else
00405 {
00406
00407 index -= ic - 1;
00408 unsigned int i, jc;
00409 for (i = 0; i < ic; i++)
00410 {
00411 jc = baseKernel[i]->getParameterDimension();
00412 if (index < jc)
00413 {
00414 baseKernel[i]->setParameter(index, value);
00415 break;
00416 }
00417 else index -= jc;
00418 }
00419 }
00420 }
00421
00422 double WeightedSumKernel::eval(const Array<double>& x1, const Array<double>& x2) const
00423 {
00424 double k = 0.0;
00425 int i, ic = baseKernel.size();
00426 for (i = 0; i < ic; i++) k += weight[i] * baseKernel[i]->eval(x1, x2);
00427 return k / weightsum;
00428 }
00429
00430 double WeightedSumKernel::evalDerivative(const Array<double>& x1, const Array<double>& x2, Array<double>& derivative) const
00431 {
00432 derivative.resize(getParameterDimension(), false);
00433
00434 int i, ic = baseKernel.size();
00435 std::vector<double> k_result(ic);
00436 Array<double> der;
00437 double k = 0.0;
00438 int p = ic - 1;
00439 int j, jc;
00440 for (i = 0; i < ic; i++)
00441 {
00442 k_result[i] = baseKernel[i]->evalDerivative(x1, x2, der);
00443 k += weight[i] * k_result[i];
00444
00445
00446 jc = baseKernel[i]->getParameterDimension();
00447 for (j = 0; j < jc; j++)
00448 {
00449 derivative(p) = weight[i] * der(j) / weightsum;
00450 p++;
00451 }
00452 }
00453
00454
00455 for (i = 0; i < ic - 1; i++)
00456 {
00457 derivative(i) = weight[i+1] * (k_result[i+1] - k / weightsum) / weightsum;
00458 }
00459
00460 return k / weightsum;
00461 }
00462
00463 bool WeightedSumKernel::isFeasible()
00464 {
00465 int i, ic = baseKernel.size();
00466 for (i = 0; i < ic; i++)
00467 {
00468 if (! baseKernel[i]->isFeasible()) return false;
00469 }
00470 return true;
00471 }
00472
00473
00475
00476
00477 WeightedSumKernel2::WeightedSumKernel2(const std::vector<KernelFunction*>& base)
00478 {
00479 int i, ic = base.size();
00480 if (ic == 0) throw SHARKEXCEPTION("[WeightedSumKernel2] There must be at least one sub-kernel.");
00481 int j, jc;
00482 int p, pc = ic;
00483 baseKernel.resize(ic);
00484 weight.resize(ic);
00485 for (i = 0; i < ic; i++)
00486 {
00487 pc += base[i]->getParameterDimension();
00488 baseKernel[i] = base[i];
00489 weight[i] = 1.0;
00490 }
00491 weightsum = ic;
00492 parameter.resize(pc, false);
00493
00494 p = 0;
00495 for (i = 0; i < ic; i++)
00496 {
00497 parameter(p) = 0.0;
00498 p++;
00499 }
00500 for (i = 0; i < ic; i++)
00501 {
00502 jc = base[i]->getParameterDimension();
00503 for (j = 0; j < jc; j++)
00504 {
00505 parameter(p) = base[i]->getParameter(j);
00506 p++;
00507 }
00508 }
00509 }
00510
00511 WeightedSumKernel2::~WeightedSumKernel2()
00512 {
00513 }
00514
00515
00516 void WeightedSumKernel2::setParameter(unsigned int index, double value)
00517 {
00518 parameter(index) = value;
00519
00520 unsigned int ic = baseKernel.size();
00521 if (index < ic)
00522 {
00523
00524 unsigned int i;
00525 double a;
00526 weightsum = 1.0;
00527 for (i = 0; i < ic; i++)
00528 {
00529 a = exp(parameter(i));
00530 weight[i] = a;
00531 weightsum += a;
00532 }
00533 }
00534 else
00535 {
00536
00537 index -= ic;
00538 unsigned int i, jc;
00539 for (i = 0; i < ic; i++)
00540 {
00541 jc = baseKernel[i]->getParameterDimension();
00542 if (index < jc)
00543 {
00544 baseKernel[i]->setParameter(index, value);
00545 break;
00546 }
00547 else index -= jc;
00548 }
00549 }
00550 }
00551
00552 double WeightedSumKernel2::eval(const Array<double>& x1, const Array<double>& x2) const
00553 {
00554 double k = 0.0;
00555 int i, ic = baseKernel.size();
00556 for (i = 0; i < ic; i++) k += weight[i] * baseKernel[i]->eval(x1, x2);
00557 return k / weightsum;
00558 }
00559
00560 double WeightedSumKernel2::evalDerivative(const Array<double>& x1, const Array<double>& x2, Array<double>& derivative) const
00561 {
00562 derivative.resize(getParameterDimension(), false);
00563
00564 int i, ic = baseKernel.size();
00565 std::vector<double> k_result(ic);
00566 Array<double> der;
00567 double k = 0.0;
00568 int p = ic;
00569 int j, jc;
00570 for (i = 0; i < ic; i++)
00571 {
00572 k_result[i] = baseKernel[i]->evalDerivative(x1, x2, der);
00573 k += weight[i] * k_result[i];
00574
00575
00576 jc = baseKernel[i]->getParameterDimension();
00577 for (j = 0; j < jc; j++)
00578 {
00579 derivative(p) = weight[i] * der(j) / weightsum;
00580 p++;
00581 }
00582 }
00583
00584
00585 for (i = 0; i < ic; i++)
00586 {
00587 derivative(i) = weight[i] * (k_result[i] - k / weightsum) / weightsum;
00588 }
00589
00590 return k / weightsum;
00591 }
00592
00593 bool WeightedSumKernel2::isFeasible()
00594 {
00595 int i, ic = baseKernel.size();
00596 for (i = 0; i < ic; i++)
00597 {
00598 if (! baseKernel[i]->isFeasible()) return false;
00599 }
00600 return true;
00601 }
00602
00603
00605
00606
00607 PrototypeKernel::PrototypeKernel(unsigned int setsize, unsigned int prototypeDim)
00608 {
00609 if (prototypeDim == 0) prototypeDim = setsize;
00610
00611 m_setsize = setsize;
00612 m_prototypeDim = prototypeDim;
00613 unsigned int i, total = setsize * prototypeDim;
00614 parameter.resize(total, false);
00615 parameter = 0.0;
00616 for (i=0; i<Shark::min(setsize, prototypeDim); i++) parameter(i * (prototypeDim + 1)) = 1.0;
00617 }
00618
00619 PrototypeKernel::~PrototypeKernel()
00620 {
00621 }
00622
00623
00624 double PrototypeKernel::eval(const Array<double>& x1, const Array<double>& x2) const
00625 {
00626 unsigned int i = (unsigned int)floor(x1(0));
00627 unsigned int j = (unsigned int)floor(x2(0));
00628 RANGE_CHECK(i < m_setsize);
00629 RANGE_CHECK(j < m_setsize);
00630
00631 double ret = 0.0;
00632 unsigned int p;
00633 for (p=0; p<m_prototypeDim; p++) ret += parameter(m_prototypeDim*i+p) * parameter(m_prototypeDim*j+p);
00634 return ret;
00635 }
00636
00637 double PrototypeKernel::evalDerivative(const Array<double>& x1, const Array<double>& x2, Array<double>& derivative) const
00638 {
00639 unsigned int i = (unsigned int)floor(x1(0));
00640 unsigned int j = (unsigned int)floor(x2(0));
00641 RANGE_CHECK(i < m_setsize);
00642 RANGE_CHECK(j < m_setsize);
00643
00644 derivative.resize(m_setsize * m_prototypeDim);
00645 derivative = 0.0;
00646
00647 double ret = 0.0;
00648 unsigned int p;
00649 for (p=0; p<m_prototypeDim; p++)
00650 {
00651 unsigned int ii = m_prototypeDim * i + p;
00652 unsigned int jj = m_prototypeDim * j + p;
00653 double pi = parameter(ii);
00654 double pj = parameter(jj);
00655 ret += pi * pj;
00656 derivative(ii) += pj;
00657 derivative(jj) += pi;
00658 }
00659 return ret;
00660 }
00661
00662 void PrototypeKernel::getPrototype(unsigned int n, Array<double>& vec)
00663 {
00664 RANGE_CHECK(n < m_setsize);
00665
00666 vec.resize(m_prototypeDim, false);
00667 unsigned int p;
00668 for (p=0; p<m_prototypeDim; p++) vec(p) = parameter(m_prototypeDim * n + p);
00669 }
00670
00671 void PrototypeKernel::setPrototype(unsigned int n, const Array<double>& vec)
00672 {
00673 SIZE_CHECK(vec.ndim() == 1);
00674 SIZE_CHECK(vec.dim(0) == m_prototypeDim);
00675 RANGE_CHECK(n < m_setsize);
00676
00677 unsigned int p;
00678 for (p=0; p<m_prototypeDim; p++) parameter(m_prototypeDim * n + p) = vec(p);
00679 }
00680
00681
00683
00684
00685 JointKernelFunction::JointKernelFunction(KernelFunction& inputkernel, KernelFunction& labelkernel)
00686 : m_inputkernel(inputkernel)
00687 , m_labelkernel(labelkernel)
00688 {
00689 parameter.resize(inputkernel.getParameterDimension() + labelkernel.getParameterDimension(), false);
00690 unsigned int i;
00691 for (i=0; i<inputkernel.getParameterDimension(); i++)
00692 {
00693 parameter(i) = inputkernel.getParameter(i);
00694 }
00695 for (i=0; i<labelkernel.getParameterDimension(); i++)
00696 {
00697 parameter(inputkernel.getParameterDimension() + i) = labelkernel.getParameter(i);
00698 }
00699 }
00700
00701 JointKernelFunction::~JointKernelFunction()
00702 {
00703 }
00704
00705
00706 double JointKernelFunction::eval(const Array<double>& x1, const Array<double>& y1, const Array<double>& x2, const Array<double>& y2) const
00707 {
00708 double k1 = m_inputkernel.eval(x1, x2);
00709 double k2 = m_labelkernel.eval(y1, y2);
00710 return k1 * k2;
00711 }
00712
00713 double JointKernelFunction::evalDerivative(const Array<double>& x1, const Array<double>& y1, const Array<double>& x2, const Array<double>& y2, Array<double>& derivative) const
00714 {
00715 Array<double> der1(m_inputkernel.getParameterDimension());
00716 Array<double> der2(m_labelkernel.getParameterDimension());
00717 double k1 = m_inputkernel.evalDerivative(x1, x2, der1);
00718 double k2 = m_labelkernel.evalDerivative(y1, y2, der2);
00719
00720 unsigned int i;
00721 derivative.resize(getParameterDimension(), false);
00722 for (i=0; i<m_inputkernel.getParameterDimension(); i++)
00723 derivative(i) = k2 * der1(i);
00724 for (i=0; i<m_labelkernel.getParameterDimension(); i++)
00725 derivative(m_inputkernel.getParameterDimension() + i) = k1 * der2(i);
00726
00727 return k1 * k2;
00728 }
00729
00730 void JointKernelFunction::model(const Array<double>& input, Array<double> &output)
00731 {
00732 throw SHARKEXCEPTION("[JointKernelFunction::model] never call this function - it is undefined.");
00733 }
00734
00735 void JointKernelFunction::setParameter(unsigned int index, double value)
00736 {
00737 Model::setParameter(index, value);
00738 if (index < m_inputkernel.getParameterDimension()) m_inputkernel.setParameter(index, value);
00739 else m_labelkernel.setParameter(index - m_inputkernel.getParameterDimension(), value);
00740 }