bool AveragingMSRowProvider::processCurrentTimestep()
{
	size_t a1 = _antenna1Column(_currentRow);
	size_t a2 = _antenna2Column(_currentRow);
	_averagedDataDescId = _currentDataDescId;
	_averagedAntenna1Index = a1;
	_averagedAntenna2Index = a2;
	
	size_t spwCount = selectedDataDescIds().size();
	size_t elementIndex = spwCount*(a2 + a1*_nAntennae) + selectedDataDescIds().find(_averagedDataDescId)->second;
	size_t avgFactor = _averagingFactors[elementIndex];
	_averageFactorSum += avgFactor;
	++_rowCount;
	
	//if(a1==1 && a2==2)
	//	Logger::Debug << a1 <<'\t' << a2 << '\t' << avgFactor << '\n';
	
	_dataColumn.get(_currentRow, _currentData);
	_flagColumn.get(_currentRow, _currentFlags);
	getCurrentWeights(_currentWeights);
	if(requireModel())
		_modelColumn->get(_currentRow, _currentModel);
	
	if(avgFactor == 1)
		return true;
	else
	{
		size_t bufferSize = DataShape()[0] * DataShape()[1];
		AveragingBuffer& buffer = _buffers[elementIndex];
		if(!buffer.IsInitialized())
			buffer.Initialize(bufferSize, requireModel());
		
		if(requireModel())
			buffer.AddDataAndModel(bufferSize, _currentData.data(), _currentModel.data(), _currentFlags.data(), _currentWeights.data(), _currentUVWArray.data(), _currentTime);
		else
			buffer.AddData(bufferSize, _currentData.data(), _currentFlags.data(), _currentWeights.data(), _currentUVWArray.data(), _currentTime);
		
		bool foundFullBuffer = (buffer.AveragedDataCount() == avgFactor);
		if(foundFullBuffer)
		{
			if(requireModel())
				buffer.Get(bufferSize, _currentData.data(), _currentModel.data(), _currentFlags.data(), _currentWeights.data(), _currentUVWArray.data(), _currentTime);
			else
				buffer.Get(bufferSize, _currentData.data(), _currentFlags.data(), _currentWeights.data(), _currentUVWArray.data(), _currentTime);
			buffer.Reset(bufferSize);
		}
		return foundFullBuffer;
	}
}
void MultiplicativeWeightsLearningModel::updateWeights(std::vector<Value> profits, Value, double phi) {

    struct StratUsage {
        Value profits;
        MinerCount minersUsing;
        
        StratUsage() : profits(0), minersUsing(0) {}
        
        void addProfit(Value profit) {
            profits += profit;
            minersUsing++;
        }
        
        void normalize() {
            if (minersUsing > MinerCount(1)) {
                profits /= Value(minersUsing);
                minersUsing = MinerCount(1);
            }
        }
        
        bool isUnused() {
            return minersUsing == MinerCount(0);
        }
        
        double profitRatio(Value maxProfits) {
            assert(profits <= maxProfits);
            return rawValue(profits/maxProfits);
        }
    };
    
    std::vector<StratUsage> stratUsages;
    stratUsages.resize(stratCount);
    
    for (size_t i = 0; i < minerCount; i++) {
        stratUsages[getChosenStrat(i)].addProfit(profits[i]);
    }
    
    Value maxProfits(0);
    for (auto &stratUsage : stratUsages) {
        stratUsage.normalize();
        if (maxProfits < stratUsage.profits) {
            maxProfits = stratUsage.profits;
        }
    }
    
    std::vector<StratWeight> newWeights;
    newWeights.reserve(stratCount);
    
    StratWeight totalWeight(0);
    for (size_t i = 0; i < stratUsages.size(); i++) {
        double c_t = 1.1 - stratUsages[i].profitRatio(maxProfits);
        if (stratUsages[i].isUnused()) {
            //means no one tried the strategy, keep weight unchanged (encourage exploration)?
            c_t = 0;
        }
        
        StratWeight newWeight = getCurrentWeight(i) * StratWeight(pow((1-phi), c_t));
        updateWeight(i, newWeight);
        totalWeight += newWeight;
        newWeights.push_back(newWeight);
    }
    
    for (size_t i = 0; i < newWeights.size(); i++) {
        updateWeight(i, newWeights[i] / totalWeight);
    }
    
    std::vector<StratWeight> weights = getCurrentWeights();
    
    probabilities.clear();
    probabilities.reserve(stratCount);
    std::transform(begin(weights), end(weights), std::back_inserter(probabilities), [](const auto &weight) { return rawWeight(weight); });
}
MultiplicativeWeightsLearningModel::MultiplicativeWeightsLearningModel(std::vector<std::unique_ptr<LearningStrategy>> &learningStrategies, size_t minerCount_, std::string resultFolder) : LearningModel(learningStrategies, minerCount_, resultFolder) {
    std::vector<StratWeight> weights = getCurrentWeights();
    probabilities.reserve(stratCount);
    std::transform(begin(weights), end(weights), std::back_inserter(probabilities), [](const auto &weight) { return rawWeight(weight); });
}