//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** @author John Miller * @version 1.6 * @date Sat Mar 27 14:40:57 EDT 2021 * @see LICENSE (MIT style license file). * * @title Model Part: Convolutional Filter (one dimensional) */ package scalation.analytics import scala.math.{min, max} import scalation.linalgebra.{FunctionV_2V, MatriD, MatrixD, VectoD, VectorD} import scalation.random.RandomVecD import scalation.util.banner //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `CoFilter_1D` class provides a convolution filter (cofilter) for * taking a weighted average over a window of an input vector. * @param width the width of the cofilter */ class CoFilter_1D (height: Int = 5, width: Int = 5) { private val rvg = RandomVecD (width, 2.0) // random vector genertor private var vec = rvg.gen // the filter's vector //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Update the parameters, i.e., the filter's vector. * @param vec the new vector parameters */ def update (vec2: VectoD): Unit = { vec = vec2 } } // CoFilter_1D class //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `Filter` object provides the convolution and pooling operators. */ object CoFilter_1D { //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the 'full' convolution of cofilter 'c' and input vector 'x'. * @param c the cofilter vector of coefficient * @param x the input/data vector */ def convf (c: VectoD, x: VectoD): VectoD = { val y = new VectorD (c.dim + x.dim - 1) for (k <- y.range) { var sum = 0.0 for (j <- 0 until min (k+1, c.dim)) { if (k - j < x.dim) sum += c(j) * x(k - j) } // for y(k) = sum } // for y } // convf //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the 'same' convolution of cofilter 'c' and input vector 'x'. * Same means that the size of the result is the same as the input. * @param c the cofilter vector of coefficient * @param x the input/data vector */ def convs (c: VectoD, x: VectoD): VectoD = { val y = new VectorD (x.dim) val off = c.dim / 2 for (k <- off until y.dim + off) { var sum = 0.0 for (j <- 0 until min (k+1, c.dim)) { if (k - j < x.dim) sum += c(j) * x(k - j) } // for y(k-off) = sum } // for y } // convs //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the 'valid' (no padding) convolution of cofilter 'c' and input vector 'x'. * Caveat: does not include reversal. * @param c the cofilter vector of coefficient * @param x the input/data vector */ def conv (c: VectoD, x: VectoD): VectoD = { val y = new VectorD (x.dim - c.dim + 1) for (k <- y.range) y(k) = x.slice (k, k + c.dim) dot c y } // conv //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the convolution over all data instances. * @param c the cofilter vector of coefficient * @param x the input/data matrix */ def conv (x: MatriD, c: VectoD): MatriD = { MatrixD (for (i <- x.range1) yield conv (x(i), c), false) } // conv //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the max-pooling results over all pooling windows. * @param x the input/data vector * @param s the the size of the pooling window */ def pool (x: VectoD, s: Int = 2): VectoD = { val p = new VectorD (x.dim / s) for (j <- p.range) { val jj = s * j p(j) = x.slice (jj, jj+s).max () } // for p } // pool //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the pooling results over all data instances. * @param x the input/data matrix * @param s the the size of the pooling window */ def pool (x: MatriD, s: Int): MatriD = { MatrixD (for (i <- x.range1) yield pool (x(i), s), false) } // conv } // CoFilter_1D object import CoFilter_1D._ //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `CoFilter_1DTest` object is used to test the `CoFilter_1D` class. * Test using the simple example from section 11.10 of ScalaTion textbook. * > runMain scalation.analytics.CoFilter_1DTest */ object CoFilter_1DTest extends App { val x = new MatrixD ((2, 5), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) val c = VectorD (0.5, 1, 0.5) val z = conv (x, c) val p = pool (z, 3) println (s"input x = $x") println (s"filter c = $c") println (s"feature map z = $z") println (s"pooled p = $p") } // CoFilter_1DTest import scala.math.min //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `CoFilterTest2` object is used to test the `CoFilter` class' * convolutional operator. * > runMain scalation.analytics.CoFilterTest2 */ object CoFilterTest2 extends App { val c = VectorD (1, 2, 3, 4, 5) val x = VectorD (1, 2, 3, 4, 5, 6, 7) banner (s"c convolution x") println (s"c = $c") println (s"x = $x") banner ("Full Convolution: convf (c, x)") println (s"y = ${convf (c, x)}") banner ("Same Convolution: convs (c, x)") println (s"y = ${convs (c, x)}") banner ("Valid Convolution: conv (c.reverse (), x)") println (s"y = ${conv (c.reverse (), x)}") } // CoFilterTest2