dist/multilabel/PassiveAggressiveHash.js
function(sample, classes) {
		var classesSet = hash.normalized(classes);

		var ranks = this.predict(sample, /*averaging=*/false);  // pairs of [class,score] sorted by decreasing score

		// find the lowest ranked relevant label r:
		var r = 0
		var r_score = Number.MAX_VALUE
		ranks.forEach(function(labelAndScore) {
			var label = labelAndScore[0];
			var score = labelAndScore[1];
			if ((label in classesSet) && score < r_score) {
				r = label
				r_score = score
			}
		});

		// find the highest ranked irrelevant label s
		var s = 0
		var s_score = -Number.MAX_VALUE
		ranks.reverse();
		ranks.forEach(function(labelAndScore) {
			var label = labelAndScore[0];
			var score = labelAndScore[1];
			if (!(label in classesSet) && score > s_score) {
				s = label;
				s_score = score;
			}
		});

		var loss = Math.max(1.0 - r_score, 0.0) + Math.max(1.0 + s_score, 0.0);
		if (loss > 0) {
			var sample_norm2 = hash.sum_of_square_values(sample);
			var tau = Math.min(this.Constant, loss / sample_norm2);

			if (r_score < Number.MAX_VALUE)
				hash.addtimes(this.weights[r], tau, sample);  // weights[r] += tau*sample
			if (s_score > -Number.MAX_VALUE)
				hash.addtimes(this.weights[s], -tau, sample); // weights[s] -= tau*sample
		}
		// this.weights_sum = (this.weights + this.weights_sum);
		for (category in this.weights)
			hash.add(this.weights_sum[category], this.weights[category]);
		
		hash.add(this.seenFeatures, sample);
		this.num_iterations += 1;
	}
function(sample, classes) {
		var classesSet = hash.normalized(classes);

		var ranks = this.predict(sample, /*averaging=*/false);  // pairs of [class,score] sorted by decreasing score

		// find the lowest ranked relevant label r:
		var r = 0
		var r_score = Number.MAX_VALUE
		ranks.forEach(function(labelAndScore) {
			var label = labelAndScore[0];
			var score = labelAndScore[1];
			if ((label in classesSet) && score < r_score) {
				r = label
				r_score = score
			}
		});

		// find the highest ranked irrelevant label s
		var s = 0
		var s_score = -Number.MAX_VALUE
		ranks.reverse();
		ranks.forEach(function(labelAndScore) {
			var label = labelAndScore[0];
			var score = labelAndScore[1];
			if (!(label in classesSet) && score > s_score) {
				s = label;
				s_score = score;
			}
		});

		var loss = Math.max(1.0 - r_score, 0.0) + Math.max(1.0 + s_score, 0.0);
		if (loss > 0) {
			var sample_norm2 = hash.sum_of_square_values(sample);
			var tau = Math.min(this.Constant, loss / sample_norm2);

			if (r_score < Number.MAX_VALUE)
				hash.addtimes(this.weights[r], tau, sample);  // weights[r] += tau*sample
			if (s_score > -Number.MAX_VALUE)
				hash.addtimes(this.weights[s], -tau, sample); // weights[s] -= tau*sample
		}
		// this.weights_sum = (this.weights + this.weights_sum);
		for (category in this.weights)
			hash.add(this.weights_sum[category], this.weights[category]);
		
		hash.add(this.seenFeatures, sample);
		this.num_iterations += 1;
	}
Tell the classifier that the given sample belongs to the given classes.

@param sample a hash of feature-values (string features)
@param classes an array whose VALUES are classes.