docs: function (Y) {
  			var N = this.N;
  			var dim = this.dim; // dim of output space
  			var P = this.P;
  
  			var pmul = this.iter < 100 ? 4 : 1; // trick that helps with local optima
  
  			// compute current Q distribution, unnormalized first
  			var Qu = zeros(N * N);
  			var qsum = 0.0;
  			for (var i = 0; i < N; i++) {
  				for (var j = i + 1; j < N; j++) {
  					var dsum = 0.0;
  					for (var d = 0; d < dim; d++) {
  						var dhere = Y[i][d] - Y[j][d];
  						dsum += dhere * dhere;
  					}
  					var qu = 1.0 / (1.0 + dsum); // Student t-distribution
  					Qu[i * N + j] = qu;
  					Qu[j * N + i] = qu;
  					qsum += 2 * qu;
  				}
  			}
  			// normalize Q distribution to sum to 1
  			var NN = N * N;
  			var Q = zeros(NN);
  			for (var q = 0; q < NN; q++) {
  				Q[q] = Math.max(Qu[q] / qsum, 1e-100);
  			}
  
  			var cost = 0.0;
  			var grad = [];
  			for (var i = 0; i < N; i++) {
  				var gsum = new Array(dim); // init grad for point i
  				for (var d = 0; d < dim; d++) {
  					gsum[d] = 0.0;
  				}
  				for (var j = 0; j < N; j++) {
  					cost += -P[i * N + j] * Math.log(Q[i * N + j]); // accumulate cost (the non-constant portion at least...)
  					var premult = 4 * (pmul * P[i * N + j] - Q[i * N + j]) * Qu[i * N + j];
  					for (var d = 0; d < dim; d++) {
  						gsum[d] += premult * (Y[i][d] - Y[j][d]);
  					}
  				}
  				grad.push(gsum);
  			}
  
  			return {
  				cost: cost,
  				grad: grad
  			};
  		}