func (e *Ensemble) PredictCSR(indptr []int, cols []int, vals []float64, predictions []float64, nEstimators int, nThreads int) error {
	nRows := len(indptr) - 1
	if len(predictions) < e.NOutputGroups()*nRows {
		return fmt.Errorf("predictions slice too short (should be at least %d)", e.NOutputGroups()*nRows)
	}
	nEstimators = e.adjustNEstimators(nEstimators)
	err := e.checkNEstimators(nEstimators)
	if err != nil {
		return err
	}
	if nRows <= BatchSize || nThreads == 0 || nThreads == 1 {
		fvals := make([]float64, e.NFeatures())
		e.resetFVals(fvals)
		e.predictCSRInner(indptr, cols, vals, 0, len(indptr)-1, predictions, nEstimators, fvals)
		return nil
	}
	if nThreads > runtime.GOMAXPROCS(0) || nThreads < 1 {
		nThreads = runtime.GOMAXPROCS(0)
	}
	nBatches := int(math.Ceil(float64(nRows) / BatchSize))
	if nThreads > nBatches {
		nThreads = nBatches
	}
	tasks := make(chan int)
	wg := sync.WaitGroup{}
	for i := 0; i < nThreads; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			fvals := make([]float64, e.NFeatures())
			e.resetFVals(fvals)
			for startIndex := range tasks {
				endIndex := startIndex + BatchSize
				if endIndex > nRows {
					endIndex = nRows
				}
				e.predictCSRInner(indptr, cols, vals, startIndex, endIndex, predictions, nEstimators, fvals)
			}
		}()
	}
	for i := 0; i < nBatches; i++ {
		tasks <- i * BatchSize
	}
	close(tasks)
	wg.Wait()
	return nil
}
PredictCSR calculates predictions from ensemble. `indptr`, `cols`, `vals`
represent data structures from Compressed Sparse Row Matrix format (see
CSRMat). Only `nEstimators` first estimators (trees) will be used.
`nThreads` points to number of threads that will be utilized (maximum
is GO_MAX_PROCS)
Note, `predictions` slice should be properly allocated on call side
package leaves
import (
	"fmt"
	"math"
	"runtime"
	"sync"
	"github.com/dmitryikh/leaves/transformation"
)
const BatchSize = 16
type ensembleBaseInterface interface {
	NEstimators() int
	NRawOutputGroups() int
	NFeatures() int
	NLeaves() []int
	Name() string
	adjustNEstimators(nEstimators int) int
	predictInner(fvals []float64, nEstimators int, predictions []float64, startIndex int)
	predictLeafIndicesInner(fvals []float64, nEstimators int, predictions []float64, startIndex int)
	resetFVals(fvals []float64)
}
type Ensemble struct {
	ensembleBaseInterface
	transform transformation.Transform
}
func (e *Ensemble) predictInnerAndTransform(fvals []float64, nEstimators int, predictions []float64, startIndex int) {
	if e.Transformation().Type() == transformation.Raw {
		e.predictInner(fvals, nEstimators, predictions, startIndex)
	} else if e.Transformation().Type() == transformation.LeafIndex {
		e.predictLeafIndicesInner(fvals, nEstimators, predictions, startIndex)
	} else {
		rawPredictions := make([]float64, e.NRawOutputGroups())
		e.predictInner(fvals, nEstimators, rawPredictions, 0)
		e.transform.Transform(rawPredictions, predictions, startIndex)
	}
}
func (e *Ensemble) checkNEstimators(nEstimators int) error {
	if e.transform.Type() == transformation.LeafIndex && nEstimators != e.NEstimators() {
		return fmt.Errorf("while predicting leaf indices all estimators should be used (provided num. of estimators = %d, should be %d)",
			nEstimators, e.NEstimators())
	}
	return nil
}
func (e *Ensemble) PredictSingle(fvals []float64, nEstimators int) float64 {
	if e.NOutputGroups() != 1 {
		return 0.0
	}
	if e.NFeatures() > len(fvals) {
		return 0.0
	}
	nEstimators = e.adjustNEstimators(nEstimators)
	err := e.checkNEstimators(nEstimators)
	if err != nil {
		return 0.0
	}
	ret := [1]float64{0.0}
	e.predictInnerAndTransform(fvals, nEstimators, ret[:], 0)
	return ret[0]
}
func (e *Ensemble) Predict(fvals []float64, nEstimators int, predictions []float64) error {
	nRows := 1
	if len(predictions) < e.NOutputGroups()*nRows {
		return fmt.Errorf("predictions slice too short (should be at least %d)", e.NOutputGroups()*nRows)
	}
	if e.NFeatures() > len(fvals) {
		return fmt.Errorf("incorrect number of features (%d)", len(fvals))
	}
	nEstimators = e.adjustNEstimators(nEstimators)
	err := e.checkNEstimators(nEstimators)
	if err != nil {
		return err
	}
	e.predictInnerAndTransform(fvals, nEstimators, predictions, 0)
	return nil
}