Пример #1
0
    double weakBoundDistance(const VList & oldV, const VList & newV) {
        // Here we implement a weak bound (can also be seen in Cassandra's code)
        // This is mostly because a strong bound is more costly (it requires performing
        // multiple LPs) and also the code at the moment does not support it cleanly, so
        // I prefer waiting until I have a good implementation of an LP class that hides
        // complexity from here.
        //
        // The logic of the weak bound is the following: the variation between the old
        // VList and the new one is equal to the maximum distance between a ValueFunction
        // in the old VList with its closest match in the new VList. So the farthest from
        // closest.
        //
        // We define distance between two ValueFunctions as the maximum between their
        // element-wise difference.
        if ( !oldV.size() ) return 0.0;

        double distance = 0.0;
        for ( const auto & newVE : newV ) {
            // Initialize closest distance for newVE as infinity
            double closestDistance = std::numeric_limits<double>::infinity();
            for ( const auto & oldVE : oldV ) {
                // Compute the distance, we pick the max
                double distance = (newVE.values - oldVE.values).cwiseAbs().maxCoeff();

                // Keep the closest, we pick the min
                closestDistance = std::min(closestDistance, distance);
            }
            // Keep the maximum distance between a new VList and its closest old VList
            distance = std::max(distance, closestDistance);
        }
        return distance;
    }
Пример #2
0
void N2FNewsManager::SortByDate()
{
	VList tempList;
	while (messages->Size())
	{
		tempList.PushBack(*(messages->Begin()));
		messages->Erase(messages->Begin());
	}

	while (tempList.Size())
	{
		VList::Iterator maxIt;
		N2FMessage *curMax = NULL;
		for (VList::Iterator it = tempList.Begin(); it != tempList.End(); it++)
		{
			N2FMessage *tmp = (N2FMessage*)(*it);
			if (!curMax || IsHigher(curMax, tmp))
			{
				curMax = tmp;
				maxIt = it;
			}
		}
		messages->PushBack(curMax);
		tempList.Erase(maxIt);
	}
}
Пример #3
0
        VList IncrementalPruning::crossSum(const VList & l1, const VList & l2, size_t a, bool order) {
            VList c;

            if ( ! ( l1.size() && l2.size() ) ) return c;

            // We can get the sizes of the observation vectors
            // outside since all VEntries for our input VLists
            // are guaranteed to be sized equally.
            const auto O1size  = std::get<OBS>(l1[0]).size();
            const auto O2size  = std::get<OBS>(l2[0]).size();
            for ( const auto & v1 : l1 ) {
                auto O1begin = std::begin(std::get<OBS>(v1));
                auto O1end   = std::end  (std::get<OBS>(v1));
                for ( const auto & v2 : l2 ) {
                    auto O2begin = std::begin(std::get<OBS>(v2));
                    auto O2end   = std::end  (std::get<OBS>(v2));
                    // Cross sum
                    auto v = std::get<VALUES>(v1) + std::get<VALUES>(v2);

                    // This step now depends on which order the two lists
                    // are. This function is only used in this class, so we
                    // know that the two lists are "adjacent"; however one
                    // is after the other. `order` tells us which one comes
                    // first, and we join the observation vectors accordingly.
                    VObs obs; obs.reserve(O1size + O2size);
                    if ( order ) {
                        obs.insert(std::end(obs),O1begin, O1end);
                        obs.insert(std::end(obs),O2begin, O2end);
                    } else {
                        obs.insert(std::end(obs),O2begin, O2end);
                        obs.insert(std::end(obs),O1begin, O1end);
                    }
                    c.emplace_back(std::move(v), a, std::move(obs));
                }
            }

            return c;
        }
Пример #4
0
    std::tuple<double, ValueFunction> IncrementalPruning::operator()(const M & model) {
        // Initialize "global" variables
        S = model.getS();
        A = model.getA();
        O = model.getO();

        auto v = makeValueFunction(S); // TODO: May take user input

        unsigned timestep = 0;

        Pruner prune(S);
        Projecter projecter(model);

        const bool useTolerance = checkDifferentSmall(tolerance_, 0.0);
        double variation = tolerance_ * 2; // Make it bigger
        while ( timestep < horizon_ && ( !useTolerance || variation > tolerance_ ) ) {
            ++timestep;

            // Compute all possible outcomes, from our previous results.
            // This means that for each action-observation pair, we are going
            // to obtain the same number of possible outcomes as the number
            // of entries in our initial vector w.
            auto projs = projecter(v[timestep-1]);

            size_t finalWSize = 0;
            // In this method we split the work by action, which will then
            // be joined again at the end of the loop.
            for ( size_t a = 0; a < A; ++a ) {
                // We prune each outcome separately to be sure
                // we do not replicate work later.
                for ( size_t o = 0; o < O; ++o ) {
                    const auto begin = std::begin(projs[a][o]);
                    const auto end   = std::end  (projs[a][o]);
                    projs[a][o].erase(prune(begin, end, unwrap), end);
                }

                // Here we reduce at the minimum the cross-summing, by alternating
                // merges. We pick matches like a reverse binary tree, so that
                // we always pick lists that have been merged the least.
                //
                // Example for O==7:
                //
                //  0 <- 1    2 <- 3    4 <- 5    6
                //  0 ------> 2         4 ------> 6
                //            2 <---------------- 6
                //
                // In particular, the variables are:
                //
                // - oddOld:   Whether our starting step has an odd number of elements.
                //             If so, we skip the last one.
                // - front:    The id of the element at the "front" of our current pass.
                //             note that since passes can be backwards this can be high.
                // - back:     Opposite of front, which excludes the last element if we
                //             have odd elements.
                // - stepsize: The space between each "first" of each new merge.
                // - diff:     The space between each "first" and its match to merge.
                // - elements: The number of elements we have left to merge.

                bool oddOld = O % 2;
                int i, front = 0, back = O - oddOld, stepsize = 2, diff = 1, elements = O;
                while ( elements > 1 ) {
                    for ( i = front; i != back; i += stepsize ) {
                        projs[a][i] = crossSum(projs[a][i], projs[a][i + diff], a, stepsize > 0);
                        const auto begin = std::begin(projs[a][i]);
                        const auto end   = std::end  (projs[a][i]);
                        projs[a][i].erase(prune(begin, end, unwrap), end);
                        --elements;
                    }

                    const bool oddNew = elements % 2;

                    const int tmp   = back;
                    back      = front - ( oddNew ? 0 : stepsize );
                    front     = tmp   - ( oddOld ? 0 : stepsize );
                    stepsize *= -2;
                    diff     *= -2;

                    oddOld = oddNew;
                }
                // Put the result where we can find it
                if (front != 0)
                    projs[a][0] = std::move(projs[a][front]);
                finalWSize += projs[a][0].size();
            }
            VList w;
            w.reserve(finalWSize);

            // Here we don't have to do fancy merging since no cross-summing is involved
            for ( size_t a = 0; a < A; ++a )
                w.insert(std::end(w), std::make_move_iterator(std::begin(projs[a][0])), std::make_move_iterator(std::end(projs[a][0])));

            // We have them all, and we prune one final time to be sure we have
            // computed the parsimonious set of value functions.
            const auto begin = std::begin(w);
            const auto end   = std::end  (w);
            w.erase(prune(begin, end, unwrap), end);

            v.emplace_back(std::move(w));

            // Check convergence
            if ( useTolerance )
                variation = weakBoundDistance(v[timestep-1], v[timestep]);
        }

        return std::make_tuple(useTolerance ? variation : 0.0, v);
    }