/** * Copyright (c) 2013-2017 Patrick Nicolas - Scala for Machine Learning - All rights reserved * * Licensed under the Apache License, Version 2.0 (the "License") you may not use this file * except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * The source code in this file is provided by the author for the sole purpose of illustrating the * concepts and algorithms presented in "Scala for Machine Learning 2nd edition". * ISBN: 978-1-783355-874-2 Packt Publishing. * * Version 0.99.2 */ package org.scalaml.supervised.svm.kernel import org.scalaml.Predef.DblVec import scala.language.implicitConversions import org.scalaml.core.functional._Monad /** * Experimental monad to support functional definition of kernels * @since 0.99.1 (rev. 1) */ private[scalaml] object KernelMonad { type F1 = Double => Double type F2 = (Double, Double) => Double case class KF[G](g: G, h: F2) { def metric(v: DblVec, w: DblVec)(implicit gf: G => F1): Double = g(v.zip(w).map { case (_v, _w) => h(_v, _w) }.sum) } implicit def hg2KF[G](hg: (G, F2)): KF[G] = KF(hg._1, hg._2) val identity = (x: Double, y: Double) => x * y val kfMonad = new _Monad[KF] { override def unit[G](g: G): KF[G] = KF[G](g, identity) override def map[G, H](kf: KF[G])(f: G => H): KF[H] = KF[H](f(kf.g), kf.h) override def flatMap[G, H](kf: KF[G])(f: G => KF[H]): KF[H] = KF[H](f(kf.g).g, kf.h) } implicit class kF2Monad[G](kf: KF[G]) { def map[H](f: G => H): KF[H] = kfMonad.map(kf)(f) def flatMap[H](f: G => KF[H]): KF[H] = kfMonad.flatMap(kf)(f) } class RBF(s2: Double) extends KF[F1]((x: Double) => Math.exp(-0.5 * x * x / s2), (x: Double, y: Double) => x - y) class Polynomial(d: Int) extends KF[F1]((x: Double) => Math.pow(1.0 + x, d), (x: Double, y: Double) => x * y) } private[scalaml] object KernelMonadApp extends { import KernelMonad._ val v = Vector[Double](0.5, 0.2, 0.3) val w = Vector[Double](0.1, 0.7, 0.2) val composed = for { kf1 <- new RBF(0.6) kf2 <- new Polynomial(6) } yield kf2 composed.metric(v, w) } // ------------------------------- EOF ------------------------------------