/*
 * Copyright (C) 2016 Stefan Henß
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.insightml.models.meta;

import java.util.Random;

import org.apache.commons.math3.util.Pair;

import com.insightml.data.samples.ISamples;
import com.insightml.data.samples.Sample;
import com.insightml.models.ILearner;
import com.insightml.models.IModel;
import com.insightml.models.LearnerArguments;
import com.insightml.models.LearnerInput;
import com.insightml.models.meta.VoteModel.VoteStrategy;
import com.insightml.utils.Arguments;
import com.insightml.utils.IArguments;
import com.insightml.utils.jobs.ParallelFor;

public class Bagging<I extends Sample> extends AbstractEnsembleLearner<I, Object, Double> {
	private final VoteStrategy strategy;

	public Bagging(final IArguments arguments, final ILearner<I, ? extends Object, Double>... learner) {
		super(arguments, learner);
		this.strategy = VoteStrategy.AVERAGE;
	}

	public Bagging(final int bags, final double isample, final double fsample, final VoteStrategy strategy,
			final ILearner<I, ? extends Object, Double>... learner) {
		super(new Arguments("bags", bags, "isample", isample, "fsample", fsample), learner);
		this.strategy = strategy;
	}

	@Override
	public LearnerArguments arguments() {
		final LearnerArguments args = new LearnerArguments();
		args.add("bags", 10.0, 5, 1000);
		args.add("isample", 0.8, 0.1, 1.0);
		args.add("fsample", 0.9, 0.05, 1.0);
		return args;
	}

	@Override
	protected IModel<I, Double> createModel(final ISamples<I, Object> instances,
			final ILearner<I, ? extends Object, Double>[] learner, final int labelIndex) {
		final int bags = (int) argument("bags");
		final double instancesSample = argument("isample");
		final double featureSample = argument("fsample");
		final IModel<I, Double>[] models = new IModel[bags];
		final double[] weights = new double[bags];
		ParallelFor.run(i -> {
			final Random random = new Random((long) Math.pow(i + 2, 2));
			final Pair<ISamples<I, Object>, ISamples<I, Object>> sub = instances.sample(instancesSample, random);
			models[i] = learner[i % learner.length].run(
					new LearnerInput(sub.getFirst().sampleFeatures(featureSample, random), null, null, labelIndex));
			weights[i] = 1;
			return 1;
		}, 0, bags, 3);
		return new VoteModel<>(models, weights, strategy);
	}

}

@@ -654,52 +654,8 @@
 m;%0A%0A
-import org.apache.commons.math3.util.Pair;%0A%0A
 impo
@@ -1800,17 +1800,17 @@
 , 10.0, 
-5
+2
 , 1000);
@@ -2428,13 +2428,8 @@
 nal 
-Pair%3C
 ISam
@@ -2447,36 +2447,36 @@
 ect%3E
-, ISamples%3CI, Object%3E%3E sub =
+ sub = instancesSample %3C 1 ?
  ins
@@ -2513,16 +2513,44 @@
  random)
+.getFirst()%0A%09%09%09%09%09: instances
 ;%0A%09%09%09mod
@@ -2590,22 +2590,16 @@
 th%5D.run(
-%0A%09%09%09%09%09
 new Lear
@@ -2611,22 +2611,37 @@
 put(
-sub.getFirst()
+%0A%09%09%09%09%09featureSample %3C 1 ? sub
 .sam
@@ -2674,16 +2674,22 @@
  random)
+ : sub
 , null, 

allow deactivating sampling