2
\$\begingroup\$

I'm a mathematician who is new to programming and I'm currently reading the book "Theory of Neural Networks" by Rojas. To become better, I try to program every algorithm that is described in the book using javascript (to be precise: the p5js editor). Let \$X=\{x_{1},\ldots,x_{N}\}\subset\mathbb{R}^{n}\$ be a set of points viewed as vectors. Let's assume I want to find \$ k\$ clusters in the set \$X\$. The algorithm goes as follows:

start: Initialize a set of \$k\$ normalized random vectors \$\{w_{1},\ldots,w_{k}\}\$, called weight vectors.

test: Select \$x_{j}\in X\$ randomly and compute the dotproduct \$x_{j}\cdot w_{i}\,\forall\,i\in\{1,\ldots,k\}\$. Find \$m\in\{1,\ldots,k\}\$ such that \$x_{j}\cdot w_{m}\geq x_{j}\cdot w_{i}\,\,\forall\,i\in\{1,\ldots,k\}\$.

corrcet: Substitute \$w_{m}\$ by \$w_{m}+x_{j}\$ and normalize. Then go back to test.

Here is my code:

let off = 20;  // offset to not touch boundary

class Point {
  constructor() {
    this.x = random(-width/2 + off , width / 2 - off);
    this.y = random(-height / 2 + off, height / 2 - off);
  }
  show() {
    stroke(239, 12, 12);
    strokeWeight(4);
    point(this.x, this.y);
  }
}

// function for initializing random weight vectors
function setWeights(l) {
  let weights = [];
  let v;
  for (let i = 0; i < l; i++) {
    v = createVector(
      random(-width / 2 , width / 2 ),
      random(-height / 2 , height / 2 )
    );
    weights.push(p5.Vector.mult(v, 1 / v.mag()));
  }
  return weights;
}

// k = # of weight vectors, N = # of learningsessions
function computeClusters(inpts, k, N) {
  let w = setWeights(k);
  let erg, dotprods, ind, e, m, maxIndex;
  for (let j = 0; j < N; j++) {
    dotprods = [];
    ind = floor(random(0, inpts.length));
    e = inpts[ind];
    for (let i = 0; i < w.length; i++) {
      dotprods.push(e.dot(w[i]));
    }
    m = max(dotprods);
    maxIndex = 0;
    for (let i = 0; i < dotprods.length; i++) {
      if (dotprods[i] == m) {
        maxIndex = i;
      }
    }
    erg = e.add(w[maxIndex]);
    w[maxIndex] = erg.mult(100/erg.mag());
  }
  return w;
}

// function for displaying vector in an "appropriate" way
function drawVector(vec, mycolor) {
  let arrowSize = vec.mag() / 10;
  push();
  stroke(mycolor);
  strokeWeight(1.5);
  fill(mycolor);
  line(0, 0, vec.x, vec.y);
  rotate(vec.heading());
  translate(vec.mag() - arrowSize, 0);
  triangle(0, arrowSize / 4, 0, -arrowSize / 4, arrowSize, 0);
  pop();
}

let points = [];
let vectors = [];
let w = [];
function setup() {
  createCanvas(400, 400);
  for (let i = 0; i < 10; i++) {
    let p = new Point();
    points.push(p);
    vectors.push(createVector(p.x, p.y));
  }
  w = computeClusters(vectors, 3, 10);
}

function draw() {
  background(165, 195, 239);
  translate(width / 2, height / 2);
  scale(1, -1);
  push();
  strokeWeight(0.5);
  stroke(125);
  line(-width / 2, 0, width / 2, 0);
  line(0, -height / 2, 0, height / 2);
  pop();
  for (var i = 0; i < points.length; i++) {
    points[i].show();
  }
  push();
  for (let j = 0; j < w.length; j++) {
    drawVector(w[j], color(50, 175, 150));
  }
  pop();
}

enter image description here

enter image description here

Now, the algorithm seems to performe quite well, see the attached pictures. The only problem I have is: why does my code sometimes produce two and sometimes produce three weight vecotrs, although I declared to create three: see w = computeClusters(vectors, 3, 10);?

Thanks in advance for your help. If you have any general suggestions regarding my code, feel free to give me some input. :)

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.