protected boolean doOnePassGaussian(double[][][] x, double[] tl1, boolean isFullPass, boolean[] activeSet,
			double[][] w, double[] stepSize, double[] g, double[] gradient, double[] rTrain) {
		boolean activeSetChanged = false;

		for (int k = 0; k < x.length; k++) {
			if (!isFullPass && !activeSet[k]) {
				continue;
			}

			double[][] block = x[k];
			double[] beta = w[k];
			double tk = stepSize[k];

			// Proximal gradient method
			computeGradient(block, rTrain, gradient);

			for (int j = 0; j < beta.length; j++) {
				g[j] = beta[j] + tk * gradient[j];
			}

			double norm = Math.sqrt(StatUtils.sumSq(g, 0, beta.length));
			double lambda = tl1[k] * tk;
			if (norm > lambda) {
				VectorUtils.multiply(g, (1 - lambda / norm));
			} else {
				Arrays.fill(g, 0);
			}

			// Update residuals
			for (int j = 0; j < beta.length; j++) {
				double[] t = block[j];
				double delta = beta[j] - g[j];
				for (int i = 0; i < rTrain.length; i++) {
					rTrain[i] += delta * t[i];
				}
			}

			// Update weights
			for (int j = 0; j < beta.length; j++) {
				beta[j] = g[j];
			}

			if (isFullPass && !activeSet[k] && !ArrayUtils.isConstant(beta, 0, beta.length, 0)) {
				activeSetChanged = true;
				activeSet[k] = true;
			}
		}

		return activeSetChanged;
	}