code: function () {
  			this.iter += 1;
  			var N = this.N;
  
  			var cg = this.costGrad(this.Y); // evaluate gradient
  			var cost = cg.cost;
  			var grad = cg.grad;
  
  			// perform gradient step
  			var ymean = zeros(this.dim);
  			for (var i = 0; i < N; i++) {
  				for (var d = 0; d < this.dim; d++) {
  					var gid = grad[i][d];
  					var sid = this.ystep[i][d];
  					var gainid = this.gains[i][d];
  
  					// compute gain update
  					var newgain = sign(gid) === sign(sid) ? gainid * 0.8 : gainid + 0.2;
  					if (newgain < 0.01) newgain = 0.01; // clamp
  					this.gains[i][d] = newgain; // store for next turn
  
  					// compute momentum step direction
  					var momval = this.iter < 250 ? 0.5 : 0.8;
  					var newsid = momval * sid - this.epsilon * newgain * grad[i][d];
  					this.ystep[i][d] = newsid; // remember the step we took
  
  					// step!
  					this.Y[i][d] += newsid;
  
  					ymean[d] += this.Y[i][d]; // accumulate mean so that we can center later
  				}
  			}
  
  			// reproject Y to be zero mean
  			for (var i = 0; i < N; i++) {
  				for (var d = 0; d < this.dim; d++) {
  					this.Y[i][d] -= ymean[d] / N;
  				}
  			}
  
  			//if(this.iter%100===0) console.log('iter ' + this.iter + ', cost: ' + cost);
  			return cost; // return current cost
  		}
docs: perform a single step of optimization to improve the embedding