I am working on a restricted Boltzmann machine in Scala, for my class...yes I'd rather use python. Anyway, I have errors that I honestly have no idea how to fix. The error that I am having is that the error of each epoch in the machine as it learns does not decrease. Since Scala does not have its own matrix class, I created my own and I believe it all works... Since the epoch error does not decrease and after spending hours on this assignment, I have resorted to posting the code here. If you notice any bugs in this section of code, please let me know. Thanks!

```
import scala.util.Random
class Matrix2D (private var sizeX: Int, private var sizeY: Int) {
private var matrix = Array.ofDim[Double](sizeX, sizeY)
implicit def bool2int(b:Boolean) = if (b) 1 else 0
var randomGenerator = new MersenneTwister(1234)
//insert is for inserting a new row or column, is inserted to beginning of either rows or columns
def insert(axis: Int): Unit ={ //works
if (axis == 0){
sizeX += 1
val t = Array.ofDim[Double](sizeX, sizeY)
matrix = copy((1,0), matrix, t)
} else {
sizeY += 1
val t = Array.ofDim[Double](sizeX, sizeY)
matrix = copy((0,1), matrix, t)
}
}
def insert(axis: Int, value: Double): Unit ={ //works
if (axis == 0){
sizeX += 1
val t = Array.fill(sizeX, sizeY)(value)
matrix = copy((1,0), matrix, t)
} else {
sizeY += 1
val t = Array.fill(sizeX, sizeY)(value)
matrix = copy((0,1), matrix, t)
}
}
//insert both row and column
def insert(offset: (Int, Int)): Unit ={ //works
sizeX = sizeX + offset._1
sizeY = sizeY + offset._2
val t = Array.ofDim[Double](sizeX, sizeY)
matrix = copy(offset, matrix, t)
}
def insert(offset: (Int, Int), value: Double): Unit ={ //works
sizeX = sizeX + offset._1
sizeY = sizeY + offset._2
val t = Array.fill(sizeX, sizeY)(value)
matrix = copy(offset, matrix, t)
}
//this enables the insert to work properly
//works
private def copy(offset: (Int, Int), source: Array[Array[Double]], destination: Array[Array[Double]]): Array[Array[Double]] ={
var dx = Math.abs(0 - offset._1)
var dy = Math.abs(0 - offset._2)
for(i <- offset._1 to destination.length - 1){
for (j <- offset._2 to destination(1).length - 1){
destination(i)(j) = source(i - dx)(j - dy)
}
}
destination
}
private def set(a: Array[Array[Double]]) = matrix = a //works
//populate matrix with random stuff
def populate(seed: Int): Unit ={//works
var r = new Random(seed)
for(i <- 0 to matrix.length - 1){
for(j <- 0 to matrix(0).length - 1){
matrix(i)(j) = Random.nextDouble()
}
}
}
def populate(seed: Int, generator: (Double, Double) => Double): Unit ={ //works
//double randomValue = rangeMin + (rangeMax - rangeMin) * r.nextDouble();
var min = -1*generator(sizeX, sizeY)
var max = generator(sizeX, sizeY)
var r = new Random(seed)
for(i <- 0 to matrix.length - 1){
for(j <- 0 to matrix(0).length - 1){
matrix(i)(j) = min + (max - min) * randomGenerator.nextDouble()//Random.nextDouble()
}
}
}
def populate: Unit ={ //works
var r = Random
for(i <- 0 to matrix.length - 1){
for(j <- 0 to matrix(0).length - 1){
matrix(i)(j) = Random.nextDouble()
}
}
}
//I have no idea if this works correctly
def dot(other: Matrix2D): Matrix2D ={
var t = matrix
t.zip(other.matrix) map { case(te, oe) => te.zip(oe).map { case (a,b) => a*b}}
//t.zip(other.matrix) map (_.zipped map (_ * _))
Matrix2D(t)
}
//make the matrix < 0
def unary_-(): Matrix2D ={
var t = matrix
for(i <- 0 until t.length - 1; j <- 0 until t(0).length - 1){
t(i)(j) = -t(i)(j)
}
Matrix2D(t)
}
//if one matrix is less than the other, make a 2darray of numerical boolean statements
def >(other: Matrix2D): Matrix2D = { //idk if this works correctly
var om = other.matrix
var newMatrix = Array.ofDim[Double](matrix.length, matrix(0).length)
for(i <- 0 to matrix.length - 1){
for (j <- 0 to matrix(0).length - 1){
try {
if (matrix(i)(j) > om(i)(j)) {
newMatrix(i)(j) = 1
} else {
newMatrix(i)(j) = 0
}
} catch {
case e: Exception =>{}
}
}
}
Matrix2D(newMatrix)
/*var t = matrix
t.zip(other.matrix) map { case(te, oe) => te.zip(oe).map { case (a,b) => (a > b):Int}}
Matrix2D(t)*/
}
//negate a matrix from another
def -(other: Matrix2D): Matrix2D = { //i think this works correctly
var l = Array.ofDim[Double](matrix.length, matrix(0).length)
for(i <- 0 to matrix.length - 1){
for(j <- 0 to matrix(0).length - 1) {
try {
l(i)(j) = matrix(i)(j) - other.matrix(i)(j)
} catch { case e: Exception => {}}
}
}
Matrix2D(l)
/*var t = matrix
t.zip(other.matrix) map { case(te, oe) => te.zip(oe).map { case (a,b) => a - b}}
Matrix2D(t)*/
}
def /(value: Double): Matrix2D ={ //idk if this works correctly
var t = matrix
for(i <- 0 to t.length - 1; j <- 0 to t(0).length - 1){
t(i)(j) = t(i)(j) / value
}
Matrix2D(t)
}
def *(value: Double): Matrix2D ={ //idk if this works correctly
var t = matrix
for(i <- 0 to t.length - 1; j <- 0 to t(0).length - 1){
t(i)(j) = t(i)(j) * value
}
Matrix2D(t)
}
def ^(value: Int): Matrix2D = { //this works I think
var t = matrix
val m = matrix
for(i <- 0 to value-2) {
t = mult(t, m)
}
Matrix2D(t)
}
def mult(a: Array[Array[Double]], b: Array[Array[Double]])(implicit n: Numeric[Double]) = { //called by previous def (^)
for (row <- a)
yield for(col <- b.transpose)
yield row zip col map Function.tupled(_*_) reduceLeft (_+_)
}
def T: Matrix2D ={ //this works
var t = matrix.transpose
Matrix2D(t)
}
def exp(matrix: Matrix2D): Matrix2D ={ //this works
var t = matrix.matrix
for(i <- 0 to t.length - 1; j <- 0 to t(0).length - 1){
t(i)(j) = Math.exp(t(i)(j))
}
Matrix2D(t)
}
def div(value: Double): Matrix2D ={ //this works?
var t = matrix
for(i <- 0 to t.length - 1; j <- 0 to t(0).length - 1){
t(i)(j) = value / t(i)(j)
}
Matrix2D(t)
}
def +(value: Double): Matrix2D = { //this works, I think
var t = matrix
for(i <- 0 to t.length - 1; j <- 0 to t(0).length - 1){
t(i)(j) = t(i)(j) + value
}
Matrix2D(t)
}
def +(other: Matrix2D): Matrix2D = {//not sure if this works
var l = Array.ofDim[Double](matrix.length, matrix(0).length)
for(i <- 0 to matrix.length - 1){
for(j <- 0 to matrix(0).length - 1) {
l(i)(j) = matrix(i)(j) + other.matrix(i)(j)
}
}
Matrix2D(l)
}
def shape(axis: Int) = matrix(axis).length //works
def fix(axis: Int, value: Double): Unit ={ //works - sets a row/column to a value
if (axis == 0){
for(i <- 0 to matrix(0).length - 1){
matrix(0)(i) = value
}
}
if (axis == 1){
for(j <- 0 to matrix.length - 1){
matrix(j)(0) = value
}
}
}
def sum: Double ={ //works, gets sum
var s = 0.0
for(i <- 0 to matrix.length - 1){
for (j <- 0 to matrix(0).length - 1){
s += matrix(i)(j)
}
}
s
}
override def toString: String = { //obvious what this does
var s = "["
for(row <- matrix){
s+="["
for (cell <- row){
s += cell
s += " "
}
s += "]\n"
}
s+= "]"
s
}
}
object Matrix2D { //obviously works
def apply(X: Int, Y: Int): Matrix2D ={
new Matrix2D(X,Y)
}
def apply(array: Array[Array[Double]]): Matrix2D ={
var t = new Matrix2D(array(0).length, array(1).length)
t.set(array)
t
}
def rand(x: Int, y: Int): Matrix2D = {
var t = new Matrix2D(x,y)
t.populate
t
}
}
```

Here is the Boltzmann Machine code:

```
class rbm (val visible: Int, val hidden: Int){
val seed = 1234
var weights = Matrix2D(visible, hidden)
var rgen = (x: Double, y: Double) => 0.1 * Math.sqrt(6 / (x + y))
weights.populate(seed, rgen)
weights.insert((1,1), 0)
def train(data: Matrix2D, maxEpochs: Int = 1000, learningRate: Double = 0.1): Unit ={
var numExamples = data.shape(0)
data.insert(1, 1)
for(epoch <- 1 to maxEpochs) {
var posHiddenActivations = data dot weights
var posHiddenProbs = logistic(posHiddenActivations)
posHiddenProbs.fix(1, 1)
var posHiddenStates = posHiddenProbs > Matrix2D.rand(numExamples, hidden + 1)
var posAssociations = data.T dot posHiddenProbs
//==============================================================================
var negVisibleActivations = posHiddenStates dot weights.T
var negVisibleProbs = logistic(negVisibleActivations)
negVisibleProbs.fix(1,1)
var negHiddenActivations = negVisibleProbs dot weights
var negHiddenProbs = logistic(negHiddenActivations)
var negAssociations = negVisibleProbs.T dot negHiddenProbs
weights = weights + (((posAssociations - negAssociations) / numExamples) * learningRate)
var error = ((data - negVisibleProbs)^2).sum
println("Epoch " + epoch + ": error is " + error)
}
}
def run_visible(data: Array[Array[Double]]): Unit ={
}
def run_hidden(data: Array[Array[Double]]): Unit ={
}
def daydream(numsamples: Int): Unit ={
}
private def logistic(matrix: Matrix2D): Matrix2D ={
(matrix.exp(-matrix) + 1.0) div 1.0
}
/*
def _logistic(self, x):
return 1.0 / (1 + np.exp(-x))
*/
}
object rbm {
def apply(visible: Int, hidden: Int): rbm ={
new rbm(visible, hidden)
}
}
```