<commit_before>/*
 * paged_grid.cpp
 *
 *  Created on: 06.05.2010
 *      Author: gmueller
 */

#include "arguments.hpp"

#include "gadget/Grid.hpp"
#include "gadget/Index3.hpp"
#include "gadget/SmoothParticle.hpp"
#include "gadget/GadgetFile.hpp"
#include "gadget/Vector3.hpp"

#include <ctime>
#include <limits>
#include <algorithm>
#include <omp.h>
#include <sstream>
#include <fstream>

int sph(Arguments &arguments) {

	int size = arguments.getInt("-size", 240000);
	std::cout << "Size:           " << size << " kpc" << std::endl;

	float h = arguments.getFloat("-h", 0.7);
	std::cout << "h:              " << h << std::endl;

	size_t fileSizeKpc = arguments.getInt("-fileSize", 20000);
	std::cout << "FileSize:       " << fileSizeKpc << " kpc ";

	std::string prefix = arguments.getString("-prefix", "sph");

	bool verbose = arguments.hasFlag("-v");

	size_t bins = size / fileSizeKpc;
	Grid< std::vector<SmoothParticle> > grid(bins, size);

	std::vector < std::string > files;
	arguments.getVector("-f", files);
	for (size_t iArg = 0; iArg < files.size(); iArg++) {
		std::cout << "Open " << files[iArg] << " (" << (iArg + 1) << "/"
				<< files.size() << ")" << std::endl;

		GadgetFile file;
		file.open(files[iArg]);
		if (file.good() == false) {
			std::cerr << "Failed to open file " << files[iArg] << std::endl;
			return 1;
		}

		file.readHeader();
		int pn = file.getHeader().particleNumberList[0];
		std::cout << "  Number of SmoothParticles: " << pn << std::endl;

		std::cout << "  Read POS block" << std::endl;
		std::vector<float> pos;
		if (file.readFloatBlock("POS ", pos) == false) {
			std::cerr << "Failed to read POS block" << std::endl;
			return 1;
		}

		std::cout << "  Read BFLD block" << std::endl;
		std::vector<float> bfld;
		if (file.readFloatBlock("BFLD", bfld) == false) {
			std::cerr << "Failed to read BFLD block" << std::endl;
			return 1;
		}

		std::cout << "  Read HSML block" << std::endl;
		std::vector<float> hsml;
		if (file.readFloatBlock("HSML", hsml) == false) {
			std::cerr << "Failed to read HSML block" << std::endl;
			return 1;
		}

		for (int iP = 0; iP < pn; iP++) {
			SmoothParticle particle;
			particle.smoothingLength = hsml[iP] / h;
			particle.position.x = (pos[iP * 3] - size / 2) / h + size / 2;
			particle.position.y = (pos[iP * 3 + 1] - size / 2) / h + size / 2;
			particle.position.z = (pos[iP * 3 + 2] - size / 2) / h + size / 2;

			float norm = 1.0 / M_PI / pow(particle.smoothingLength, 3);
			particle.bfield.x = bfld[iP * 3] * norm;
			particle.bfield.y = bfld[iP * 3 + 1] * norm;
			particle.bfield.z = bfld[iP * 3 + 2] * norm;

			Vector3f l = particle.position - Vector3f(
					particle.smoothingLength * 2);
			l.clamp(0.0, size);

			Vector3f u = particle.position + Vector3f(
					particle.smoothingLength * 2);
			u.clamp(0.0, size);

			Index3 lower, upper;
			lower.x = (uint32_t) std::floor(l.x / fileSizeKpc);
			lower.y = (uint32_t) std::floor(l.y / fileSizeKpc);
			lower.z = (uint32_t) std::floor(l.z / fileSizeKpc);

			upper.x = (uint32_t) std::ceil(u.x / fileSizeKpc);
			upper.y = (uint32_t) std::ceil(u.y / fileSizeKpc);
			upper.z = (uint32_t) std::ceil(u.z / fileSizeKpc);

			if (verbose && (iP % 100000 ==0)) {
				std::cout << "Pos:" << particle.position << std::endl;
				std::cout << "SL:" << particle.smoothingLength << std::endl;
				std::cout << "Lower:" << lower << std::endl;
				std::cout << "Upper:" << upper << std::endl;
			}

			for (size_t x = lower.x; x < upper.x; x++)
				for (size_t y = lower.y; y < upper.y; y++)
					for (size_t z = lower.z; z < upper.z; z++)
						grid.get(x, y, z).push_back(particle);
		}
	}

	std::cout << "Write output" << std::endl;

	for (size_t x = 0; x < bins; x++) {
		if (verbose) {
			std::cout << "x = " << x << std::endl;
		}

		for (size_t y = 0; y < bins; y++)
			for (size_t z = 0; z < bins; z++) {
				std::stringstream sstr;
				sstr << prefix << "-" << x << "-" << y << "-" << z << ".raw";
				std::ofstream out(sstr.str().c_str(),std::ofstream::binary);
				uint32_t s = grid.get(x, y, z).size();
				if (verbose)
					std::cout << s << std::endl;
				out.write((const char *)&s, sizeof(uint32_t));
				out.write((const char *)&grid.get(x, y, z)[0], sizeof(SmoothParticle) * s);
			}

	}

	return 0;
}
<commit_msg>add amrgin<commit_after>/*
 * paged_grid.cpp
 *
 *  Created on: 06.05.2010
 *      Author: gmueller
 */

#include "arguments.hpp"

#include "gadget/Grid.hpp"
#include "gadget/Index3.hpp"
#include "gadget/SmoothParticle.hpp"
#include "gadget/GadgetFile.hpp"
#include "gadget/Vector3.hpp"

#include <ctime>
#include <limits>
#include <algorithm>
#include <omp.h>
#include <sstream>
#include <fstream>

int sph(Arguments &arguments) {

	int size = arguments.getInt("-size", 240000);
	std::cout << "Size:           " << size << " kpc" << std::endl;

	float h = arguments.getFloat("-h", 0.7);
	std::cout << "h:              " << h << std::endl;

	size_t fileSizeKpc = arguments.getInt("-fileSize", 20000);
	std::cout << "FileSize:       " << fileSizeKpc << " kpc ";

	size_t marginKpc = arguments.getInt("-margin", 500);
	std::cout << "Margin:       " << marginKpc << " kpc ";

	std::string prefix = arguments.getString("-prefix", "sph");

	bool verbose = arguments.hasFlag("-v");

	size_t bins = size / fileSizeKpc;
	Grid< std::vector<SmoothParticle> > grid(bins, size);

	std::vector < std::string > files;
	arguments.getVector("-f", files);
	for (size_t iArg = 0; iArg < files.size(); iArg++) {
		std::cout << "Open " << files[iArg] << " (" << (iArg + 1) << "/"
				<< files.size() << ")" << std::endl;

		GadgetFile file;
		file.open(files[iArg]);
		if (file.good() == false) {
			std::cerr << "Failed to open file " << files[iArg] << std::endl;
			return 1;
		}

		file.readHeader();
		int pn = file.getHeader().particleNumberList[0];
		std::cout << "  Number of SmoothParticles: " << pn << std::endl;

		std::cout << "  Read POS block" << std::endl;
		std::vector<float> pos;
		if (file.readFloatBlock("POS ", pos) == false) {
			std::cerr << "Failed to read POS block" << std::endl;
			return 1;
		}

		std::cout << "  Read BFLD block" << std::endl;
		std::vector<float> bfld;
		if (file.readFloatBlock("BFLD", bfld) == false) {
			std::cerr << "Failed to read BFLD block" << std::endl;
			return 1;
		}

		std::cout << "  Read HSML block" << std::endl;
		std::vector<float> hsml;
		if (file.readFloatBlock("HSML", hsml) == false) {
			std::cerr << "Failed to read HSML block" << std::endl;
			return 1;
		}

		for (int iP = 0; iP < pn; iP++) {
			SmoothParticle particle;
			particle.smoothingLength = hsml[iP] / h;
			particle.position.x = (pos[iP * 3] - size / 2) / h + size / 2;
			particle.position.y = (pos[iP * 3 + 1] - size / 2) / h + size / 2;
			particle.position.z = (pos[iP * 3 + 2] - size / 2) / h + size / 2;

			float norm = 1.0 / M_PI / pow(particle.smoothingLength, 3);
			particle.bfield.x = bfld[iP * 3] * norm;
			particle.bfield.y = bfld[iP * 3 + 1] * norm;
			particle.bfield.z = bfld[iP * 3 + 2] * norm;

			Vector3f l = particle.position - Vector3f(
					particle.smoothingLength * 2 + marginKpc);
			l.clamp(0.0, size);

			Vector3f u = particle.position + Vector3f(
					particle.smoothingLength * 2 + marginKpc);
			u.clamp(0.0, size);

			Index3 lower, upper;
			lower.x = (uint32_t) std::floor(l.x / fileSizeKpc);
			lower.y = (uint32_t) std::floor(l.y / fileSizeKpc);
			lower.z = (uint32_t) std::floor(l.z / fileSizeKpc);

			upper.x = (uint32_t) std::ceil(u.x / fileSizeKpc);
			upper.y = (uint32_t) std::ceil(u.y / fileSizeKpc);
			upper.z = (uint32_t) std::ceil(u.z / fileSizeKpc);

			if (verbose && (iP % 100000 ==0)) {
				std::cout << "Pos:" << particle.position << std::endl;
				std::cout << "SL:" << particle.smoothingLength << std::endl;
				std::cout << "Lower:" << lower << std::endl;
				std::cout << "Upper:" << upper << std::endl;
			}

			for (size_t x = lower.x; x < upper.x; x++)
				for (size_t y = lower.y; y < upper.y; y++)
					for (size_t z = lower.z; z < upper.z; z++)
						grid.get(x, y, z).push_back(particle);
		}
	}

	std::cout << "Write output" << std::endl;

	for (size_t x = 0; x < bins; x++) {
		if (verbose) {
			std::cout << "x = " << x << std::endl;
		}

		for (size_t y = 0; y < bins; y++)
			for (size_t z = 0; z < bins; z++) {
				std::stringstream sstr;
				sstr << prefix << "-" << x << "-" << y << "-" << z << ".raw";
				std::ofstream out(sstr.str().c_str(),std::ofstream::binary);
				uint32_t s = grid.get(x, y, z).size();
				if (verbose)
					std::cout << s << std::endl;
				out.write((const char *)&s, sizeof(uint32_t));
				out.write((const char *)&grid.get(x, y, z)[0], sizeof(SmoothParticle) * s);
			}

	}

	return 0;
}
<|endoftext|>


<commit_before>#include "dg/analysis/PointsTo/Pointer.h"
#include "dg/analysis/PointsTo/PointsToSet.h"
#include "dg/analysis/PointsTo/PointerSubgraph.h"
#include "dg/analysis/PointsTo/PointerAnalysis.h"

namespace dg {
namespace analysis {
namespace pta {

// nodes representing NULL, unknown memory
// and invalidated memory
PSNode NULLPTR_LOC(PSNodeType::NULL_ADDR);
PSNode *NULLPTR = &NULLPTR_LOC;
PSNode UNKNOWN_MEMLOC(PSNodeType::UNKNOWN_MEM);
PSNode *UNKNOWN_MEMORY = &UNKNOWN_MEMLOC;
PSNode INVALIDATED_LOC(PSNodeType::INVALIDATED);
PSNode *INVALIDATED = &INVALIDATED_LOC;

// pointers to those memory
const Pointer PointerUnknown(UNKNOWN_MEMORY, Offset::UNKNOWN);
const Pointer PointerNull(NULLPTR, 0);

// Return true if it makes sense to dereference this pointer.
// PTA is over-approximation, so this is a filter.
static inline bool canBeDereferenced(const Pointer& ptr)
{
    if (!ptr.isValid() || ptr.isInvalidated() || ptr.isUnknown())
        return false;

    // if the pointer points to a function, we can not dereference it
    if (ptr.target->getType() == PSNodeType::FUNCTION)
        return false;

    return true;
}

bool PointerAnalysis::processLoad(PSNode *node)
{
    bool changed = false;
    PSNode *operand = node->getOperand(0);

    if (operand->pointsTo.empty())
        return error(operand, "Load's operand has no points-to set");

    for (const Pointer& ptr : operand->pointsTo) {
        if (ptr.isUnknown()) {
            // load from unknown pointer yields unknown pointer
            changed |= node->addPointsTo(UNKNOWN_MEMORY);
            continue;
        }

        if (!canBeDereferenced(ptr))
            continue;

        // find memory objects holding relevant points-to
        // information
        std::vector<MemoryObject *> objects;
        getMemoryObjects(node, ptr, objects);

        PSNodeAlloc *target = PSNodeAlloc::get(ptr.target);
        assert(target && "Target is not memory allocation");

        // no objects found for this target? That is
        // load from unknown memory
        if (objects.empty()) {
            if (target->isZeroInitialized())
                // if the memory is zero initialized, then everything
                // is fine, we add nullptr
                changed |= node->addPointsTo(NULLPTR);
            else
                changed |= errorEmptyPointsTo(node, target);

            continue;
        }

        for (MemoryObject *o : objects) {
            // is the offset to the memory unknown?
            // In that case everything can be referenced,
            // so we need to copy the whole points-to
            if (ptr.offset.isUnknown()) {
                // we should load from memory that has
                // no pointers in it - it may be an error
                // FIXME: don't duplicate the code
                if (o->pointsTo.empty()) {
                    if (target->isZeroInitialized())
                        changed |= node->addPointsTo(NULLPTR);
                    else if (objects.size() == 1)
                        changed |= errorEmptyPointsTo(node, target);
                }

                // we have some pointers - copy them all,
                // since the offset is unknown
                for (auto& it : o->pointsTo) {
                    for (const Pointer &p : it.second) {
                        changed |= node->addPointsTo(p);
                    }
                }

                // this is all that we can do here...
                continue;
            }

            // load from empty points-to set
            // - that is load from unknown memory
            if (!o->pointsTo.count(ptr.offset)) {
                // if the memory is zero initialized, then everything
                // is fine, we add nullptr
                if (target->isZeroInitialized())
                    changed |= node->addPointsTo(NULLPTR);
                // if we don't have a definition even with unknown offset
                // it is an error
                // FIXME: don't triplicate the code!
                else if (!o->pointsTo.count(Offset::UNKNOWN))
                    changed |= errorEmptyPointsTo(node, target);
            } else {
                // we have pointers on that memory, so we can
                // do the work
                for (const Pointer& memptr : o->pointsTo[ptr.offset])
                    changed |= node->addPointsTo(memptr);
            }

            // plus always add the pointers at unknown offset,
            // since these can be what we need too
            if (o->pointsTo.count(Offset::UNKNOWN)) {
                for (const Pointer& memptr : o->pointsTo[Offset::UNKNOWN]) {
                    changed |= node->addPointsTo(memptr);
                }
            }
        }
    }

    return changed;
}

bool PointerAnalysis::processMemcpy(PSNode *node)
{
    bool changed = false;
    PSNodeMemcpy *memcpy = PSNodeMemcpy::get(node);
    PSNode *srcNode = memcpy->getSource();
    PSNode *destNode = memcpy->getDestination();

    std::vector<MemoryObject *> srcObjects;
    std::vector<MemoryObject *> destObjects;

    // gather srcNode pointer objects
    for (const Pointer& ptr : srcNode->pointsTo) {
        assert(ptr.target && "Got nullptr as target");

        if (!canBeDereferenced(ptr))
            continue;

        srcObjects.clear();
        getMemoryObjects(node, ptr, srcObjects);

        if (srcObjects.empty()){
            abort();
            return changed;
        }

        // gather destNode objects
        for (const Pointer& dptr : destNode->pointsTo) {
            assert(dptr.target && "Got nullptr as target");

            if (!canBeDereferenced(dptr))
                continue;

            destObjects.clear();
            getMemoryObjects(node, dptr, destObjects);

            if (destObjects.empty()) {
                abort();
                return changed;
            }

            changed |= processMemcpy(srcObjects, destObjects,
                                     ptr, dptr,
                                     memcpy->getLength());
        }
    }

    return changed;
}

bool PointerAnalysis::processMemcpy(std::vector<MemoryObject *>& srcObjects,
                                    std::vector<MemoryObject *>& destObjects,
                                    const Pointer& sptr, const Pointer& dptr,
                                    Offset len)
{
    bool changed = false;
    Offset srcOffset = sptr.offset;
    Offset destOffset = dptr.offset;

    assert(*len > 0 && "Memcpy of length 0");

    PSNodeAlloc *sourceAlloc = PSNodeAlloc::get(sptr.target);
    assert(sourceAlloc && "Pointer's target in memcpy is not an allocation");
    PSNodeAlloc *destAlloc = PSNodeAlloc::get(dptr.target);
    assert(destAlloc && "Pointer's target in memcpy is not an allocation");

    // set to true if the contents of destination memory
    // can contain null
    bool contains_null_somewhere = false;

    // if the source is zero initialized, we may copy null pointer
    if (sourceAlloc->isZeroInitialized()) {
        // if we really copy the whole object, just set it zero-initialized
        if ((sourceAlloc->getSize() != Offset::UNKNOWN) &&
            (sourceAlloc->getSize() == destAlloc->getSize()) &&
            len == sourceAlloc->getSize() && sptr.offset == 0) {
            destAlloc->setZeroInitialized();
        } else {
            // we could analyze in a lot of cases where
            // shoulde be stored the nullptr, but the question
            // is whether it is worth it... For now, just say
            // that somewhere may be null in the destination
            contains_null_somewhere = true;
        }
    }

    for (MemoryObject *destO : destObjects) {
        if (contains_null_somewhere)
            changed |= destO->addPointsTo(Offset::UNKNOWN, NULLPTR);

        // copy every pointer from srcObjects that is in
        // the range to destination's objects
        for (MemoryObject *so : srcObjects) {
            for (auto& src : so->pointsTo) { // src.first is offset,
                                             // src.second is a PointToSet

                // if the offset is inbound of the copied memory
                // or we copy from unknown offset, or this pointer
                // is on unknown offset, copy this pointer
                if (src.first.isUnknown() ||
                    srcOffset.isUnknown() ||
                    (srcOffset <= src.first &&
                     (len.isUnknown() ||
                      *src.first - *srcOffset < *len))) {

                    // copy the pointer, but shift it by the offsets
                    // we are working with
                    if (!src.first.isUnknown() && !srcOffset.isUnknown() &&
                        !destOffset.isUnknown()) {
                        // check that new offset does not overflow Offset::UNKNOWN
                        if (Offset::UNKNOWN - *destOffset <= *src.first - *srcOffset) {
                            changed |= destO->addPointsTo(Offset::UNKNOWN, src.second);
                            continue;
                        }

                        Offset newOff = *src.first - *srcOffset + *destOffset;
                        if (newOff >= destO->node->getSize() ||
                            newOff >= options.fieldSensitivity) {
                            changed |= destO->addPointsTo(Offset::UNKNOWN, src.second);
                        } else {
                            changed |= destO->addPointsTo(newOff, src.second);
                        }
                    } else {
                        changed |= destO->addPointsTo(Offset::UNKNOWN, src.second);
                    }
                }
            }
        }
    }

    return changed;
}

bool PointerAnalysis::processGep(PSNode *node) {
    bool changed = false;

    PSNodeGep *gep = PSNodeGep::get(node);
    assert(gep && "Non-GEP given");

    for (const Pointer& ptr : gep->getSource()->pointsTo) {
        Offset::type new_offset;
        if (ptr.offset.isUnknown() || gep->getOffset().isUnknown())
            // set it like this to avoid overflow when adding
            new_offset = Offset::UNKNOWN;
        else
            new_offset = *ptr.offset + *gep->getOffset();

        // in the case PSNodeType::the memory has size 0, then every pointer
        // will have unknown offset with the exception that it points
        // to the begining of the memory - therefore make 0 exception
        if ((new_offset == 0 || new_offset < ptr.target->getSize())
            && new_offset < *options.fieldSensitivity)
            changed |= node->addPointsTo(ptr.target, new_offset);
        else
            changed |= node->addPointsTo(ptr.target, Offset::UNKNOWN);
    }

    return changed;
}

bool PointerAnalysis::processNode(PSNode *node)
{
    bool changed = false;
    std::vector<MemoryObject *> objects;

#ifdef DEBUG_ENABLED
    size_t prev_size = node->pointsTo.size();
#endif

    switch(node->type) {
        case PSNodeType::LOAD:
            changed |= processLoad(node);
            break;
        case PSNodeType::STORE:
            for (const Pointer& ptr : node->getOperand(1)->pointsTo) {
                assert(ptr.target && "Got nullptr as target");

                if (!canBeDereferenced(ptr))
                    continue;

                objects.clear();
                getMemoryObjects(node, ptr, objects);
                for (MemoryObject *o : objects) {
                    for (const Pointer& to : node->getOperand(0)->pointsTo) {
                        changed |= o->addPointsTo(ptr.offset, to);
                    }
                }
            }
            break;
        case PSNodeType::INVALIDATE_OBJECT:
        case PSNodeType::FREE:
            break;
        case PSNodeType::INVALIDATE_LOCALS:
            // FIXME: get rid of this type of node
            // (make the analysis extendable and move it there)
            node->setParent(node->getOperand(0)->getSingleSuccessor()->getParent());
            break;
        case PSNodeType::GEP:
            changed |= processGep(node);
            break;
        case PSNodeType::CAST:
            // cast only copies the pointers
            for (const Pointer& ptr : node->getOperand(0)->pointsTo)
                changed |= node->addPointsTo(ptr);
            break;
        case PSNodeType::CONSTANT:
            // maybe warn? It has no sense to insert the constants into the graph.
            // On the other hand it is harmless. We can at least check if it is
            // correctly initialized 8-)
            assert(node->pointsTo.size() == 1
                   && "Constant should have exactly one pointer");
            break;
        case PSNodeType::CALL_RETURN:
            if (options.invalidateNodes) {
                for (PSNode *op : node->operands) {
                    for (const Pointer& ptr : op->pointsTo) {
                        if (!canBeDereferenced(ptr))
                            continue;
                        PSNodeAlloc *target = PSNodeAlloc::get(ptr.target);
                        assert(target && "Target is not memory allocation");
                        if (!target->isHeap() && !target->isGlobal()) {
                            changed |= node->addPointsTo(INVALIDATED);
                        }
                    }
                }
            }
            // fall-through
        case PSNodeType::RETURN:
            // gather pointers returned from subprocedure - the same way
            // as PHI works
        case PSNodeType::PHI:
            for (PSNode *op : node->operands)
                changed |= node->addPointsTo(op->pointsTo);
            break;
        case PSNodeType::CALL_FUNCPTR:
            // call via function pointer:
            // first gather the pointers that can be used to the
            // call and if something changes, let backend take some action
            // (for example build relevant subgraph)
            for (const Pointer& ptr : node->getOperand(0)->pointsTo) {
                // do not add pointers that do not point to functions
                // (but do not do that when we are looking for invalidated
                // memory as this may lead to undefined behavior)
                if (!options.invalidateNodes
                    && ptr.target->getType() != PSNodeType::FUNCTION)
                    continue;

                if (node->addPointsTo(ptr)) {
                    changed = true;

                    if (ptr.isValid() && !ptr.isInvalidated()) {
                        if (functionPointerCall(node, ptr.target))
                            recomputeSCCs();
                    } else {
                        error(node, "Calling invalid pointer as a function!");
                        continue;
                    }
                }
            }
            break;
        case PSNodeType::MEMCPY:
            changed |= processMemcpy(node);
            break;
        case PSNodeType::ALLOC:
        case PSNodeType::DYN_ALLOC:
        case PSNodeType::FUNCTION:
            // these two always points to itself
            assert(node->doesPointsTo(node, 0));
            assert(node->pointsTo.size() == 1);
        case PSNodeType::CALL:
        case PSNodeType::ENTRY:
        case PSNodeType::NOOP:
            // just no op
            break;
        default:
            assert(0 && "Unknown type");
    }

#ifdef DEBUG_ENABLED
    // the change of points-to set is not the only
    // change that can happen, so we don't use it as an
    // indicator and we use the 'changed' variable instead.
    // However, this assertion must hold:
    assert((node->pointsTo.size() == prev_size || changed)
           && "BUG: Did not set change but changed points-to sets");
#endif

    return changed;
}

void PointerAnalysis::sanityCheck() {
#ifndef NDEBUG
    assert(NULLPTR->pointsTo.size() == 1
           && "Null has been assigned a pointer");
    assert(NULLPTR->doesPointsTo(NULLPTR)
           && "Null points to a different location");
    assert(UNKNOWN_MEMORY->pointsTo.size() == 1
           && "Unknown memory has been assigned a pointer");
    assert(UNKNOWN_MEMORY->doesPointsTo(UNKNOWN_MEMORY, Offset::UNKNOWN)
           && "Unknown memory has been assigned a pointer");
    assert(INVALIDATED->pointsTo.empty()
           && "Unknown memory has been assigned a pointer");

    auto nodes = PS->getNodes(PS->getRoot());
    std::set<unsigned> ids;
    for (auto nd : nodes) {
        assert(ids.insert(nd->getID()).second && "Duplicated node ID");

        if (nd->getType() == PSNodeType::ALLOC) {
            assert(nd->pointsTo.size() == 1
                   && "Alloc does not point only to itself");
            assert(nd->doesPointsTo(nd, 0)
                   && "Alloc does not point only to itself");
        }
    }
#endif // not NDEBUG
}

} // namespace pta
} // namespace analysis
} // namespace dg
<commit_msg>PTA: use set operations instead of iterating over the sets<commit_after>#include "dg/analysis/PointsTo/Pointer.h"
#include "dg/analysis/PointsTo/PointsToSet.h"
#include "dg/analysis/PointsTo/PointerSubgraph.h"
#include "dg/analysis/PointsTo/PointerAnalysis.h"

namespace dg {
namespace analysis {
namespace pta {

// nodes representing NULL, unknown memory
// and invalidated memory
PSNode NULLPTR_LOC(PSNodeType::NULL_ADDR);
PSNode *NULLPTR = &NULLPTR_LOC;
PSNode UNKNOWN_MEMLOC(PSNodeType::UNKNOWN_MEM);
PSNode *UNKNOWN_MEMORY = &UNKNOWN_MEMLOC;
PSNode INVALIDATED_LOC(PSNodeType::INVALIDATED);
PSNode *INVALIDATED = &INVALIDATED_LOC;

// pointers to those memory
const Pointer PointerUnknown(UNKNOWN_MEMORY, Offset::UNKNOWN);
const Pointer PointerNull(NULLPTR, 0);

// Return true if it makes sense to dereference this pointer.
// PTA is over-approximation, so this is a filter.
static inline bool canBeDereferenced(const Pointer& ptr)
{
    if (!ptr.isValid() || ptr.isInvalidated() || ptr.isUnknown())
        return false;

    // if the pointer points to a function, we can not dereference it
    if (ptr.target->getType() == PSNodeType::FUNCTION)
        return false;

    return true;
}

bool PointerAnalysis::processLoad(PSNode *node)
{
    bool changed = false;
    PSNode *operand = node->getOperand(0);

    if (operand->pointsTo.empty())
        return error(operand, "Load's operand has no points-to set");

    for (const Pointer& ptr : operand->pointsTo) {
        if (ptr.isUnknown()) {
            // load from unknown pointer yields unknown pointer
            changed |= node->addPointsTo(UNKNOWN_MEMORY);
            continue;
        }

        if (!canBeDereferenced(ptr))
            continue;

        // find memory objects holding relevant points-to
        // information
        std::vector<MemoryObject *> objects;
        getMemoryObjects(node, ptr, objects);

        PSNodeAlloc *target = PSNodeAlloc::get(ptr.target);
        assert(target && "Target is not memory allocation");

        // no objects found for this target? That is
        // load from unknown memory
        if (objects.empty()) {
            if (target->isZeroInitialized())
                // if the memory is zero initialized, then everything
                // is fine, we add nullptr
                changed |= node->addPointsTo(NULLPTR);
            else
                changed |= errorEmptyPointsTo(node, target);

            continue;
        }

        for (MemoryObject *o : objects) {
            // is the offset to the memory unknown?
            // In that case everything can be referenced,
            // so we need to copy the whole points-to
            if (ptr.offset.isUnknown()) {
                // we should load from memory that has
                // no pointers in it - it may be an error
                // FIXME: don't duplicate the code
                if (o->pointsTo.empty()) {
                    if (target->isZeroInitialized())
                        changed |= node->addPointsTo(NULLPTR);
                    else if (objects.size() == 1)
                        changed |= errorEmptyPointsTo(node, target);
                }

                // we have some pointers - copy them all,
                // since the offset is unknown
                for (auto& it : o->pointsTo) {
                    changed |= node->addPointsTo(it.second);
                }

                // this is all that we can do here...
                continue;
            }

            // load from empty points-to set
            // - that is load from unknown memory
            auto it = o->pointsTo.find(ptr.offset);
            if (it == o->pointsTo.end()) {
                // if the memory is zero initialized, then everything
                // is fine, we add nullptr
                if (target->isZeroInitialized())
                    changed |= node->addPointsTo(NULLPTR);
                // if we don't have a definition even with unknown offset
                // it is an error
                // FIXME: don't triplicate the code!
                else if (!o->pointsTo.count(Offset::UNKNOWN))
                    changed |= errorEmptyPointsTo(node, target);
            } else {
                // we have pointers on that memory, so we can
                // do the work
                changed |= node->addPointsTo(it->second);
            }

            // plus always add the pointers at unknown offset,
            // since these can be what we need too
            it = o->pointsTo.find(Offset::UNKNOWN);
            if (it != o->pointsTo.end()) {
                changed |= node->addPointsTo(it->second);
            }
        }
    }

    return changed;
}

bool PointerAnalysis::processMemcpy(PSNode *node)
{
    bool changed = false;
    PSNodeMemcpy *memcpy = PSNodeMemcpy::get(node);
    PSNode *srcNode = memcpy->getSource();
    PSNode *destNode = memcpy->getDestination();

    std::vector<MemoryObject *> srcObjects;
    std::vector<MemoryObject *> destObjects;

    // gather srcNode pointer objects
    for (const Pointer& ptr : srcNode->pointsTo) {
        assert(ptr.target && "Got nullptr as target");

        if (!canBeDereferenced(ptr))
            continue;

        srcObjects.clear();
        getMemoryObjects(node, ptr, srcObjects);

        if (srcObjects.empty()){
            abort();
            return changed;
        }

        // gather destNode objects
        for (const Pointer& dptr : destNode->pointsTo) {
            assert(dptr.target && "Got nullptr as target");

            if (!canBeDereferenced(dptr))
                continue;

            destObjects.clear();
            getMemoryObjects(node, dptr, destObjects);

            if (destObjects.empty()) {
                abort();
                return changed;
            }

            changed |= processMemcpy(srcObjects, destObjects,
                                     ptr, dptr,
                                     memcpy->getLength());
        }
    }

    return changed;
}

bool PointerAnalysis::processMemcpy(std::vector<MemoryObject *>& srcObjects,
                                    std::vector<MemoryObject *>& destObjects,
                                    const Pointer& sptr, const Pointer& dptr,
                                    Offset len)
{
    bool changed = false;
    Offset srcOffset = sptr.offset;
    Offset destOffset = dptr.offset;

    assert(*len > 0 && "Memcpy of length 0");

    PSNodeAlloc *sourceAlloc = PSNodeAlloc::get(sptr.target);
    assert(sourceAlloc && "Pointer's target in memcpy is not an allocation");
    PSNodeAlloc *destAlloc = PSNodeAlloc::get(dptr.target);
    assert(destAlloc && "Pointer's target in memcpy is not an allocation");

    // set to true if the contents of destination memory
    // can contain null
    bool contains_null_somewhere = false;

    // if the source is zero initialized, we may copy null pointer
    if (sourceAlloc->isZeroInitialized()) {
        // if we really copy the whole object, just set it zero-initialized
        if ((sourceAlloc->getSize() != Offset::UNKNOWN) &&
            (sourceAlloc->getSize() == destAlloc->getSize()) &&
            len == sourceAlloc->getSize() && sptr.offset == 0) {
            destAlloc->setZeroInitialized();
        } else {
            // we could analyze in a lot of cases where
            // shoulde be stored the nullptr, but the question
            // is whether it is worth it... For now, just say
            // that somewhere may be null in the destination
            contains_null_somewhere = true;
        }
    }

    for (MemoryObject *destO : destObjects) {
        if (contains_null_somewhere)
            changed |= destO->addPointsTo(Offset::UNKNOWN, NULLPTR);

        // copy every pointer from srcObjects that is in
        // the range to destination's objects
        for (MemoryObject *so : srcObjects) {
            for (auto& src : so->pointsTo) { // src.first is offset,
                                             // src.second is a PointToSet

                // if the offset is inbound of the copied memory
                // or we copy from unknown offset, or this pointer
                // is on unknown offset, copy this pointer
                if (src.first.isUnknown() ||
                    srcOffset.isUnknown() ||
                    (srcOffset <= src.first &&
                     (len.isUnknown() ||
                      *src.first - *srcOffset < *len))) {

                    // copy the pointer, but shift it by the offsets
                    // we are working with
                    if (!src.first.isUnknown() && !srcOffset.isUnknown() &&
                        !destOffset.isUnknown()) {
                        // check that new offset does not overflow Offset::UNKNOWN
                        if (Offset::UNKNOWN - *destOffset <= *src.first - *srcOffset) {
                            changed |= destO->addPointsTo(Offset::UNKNOWN, src.second);
                            continue;
                        }

                        Offset newOff = *src.first - *srcOffset + *destOffset;
                        if (newOff >= destO->node->getSize() ||
                            newOff >= options.fieldSensitivity) {
                            changed |= destO->addPointsTo(Offset::UNKNOWN, src.second);
                        } else {
                            changed |= destO->addPointsTo(newOff, src.second);
                        }
                    } else {
                        changed |= destO->addPointsTo(Offset::UNKNOWN, src.second);
                    }
                }
            }
        }
    }

    return changed;
}

bool PointerAnalysis::processGep(PSNode *node) {
    bool changed = false;

    PSNodeGep *gep = PSNodeGep::get(node);
    assert(gep && "Non-GEP given");

    for (const Pointer& ptr : gep->getSource()->pointsTo) {
        Offset::type new_offset;
        if (ptr.offset.isUnknown() || gep->getOffset().isUnknown())
            // set it like this to avoid overflow when adding
            new_offset = Offset::UNKNOWN;
        else
            new_offset = *ptr.offset + *gep->getOffset();

        // in the case PSNodeType::the memory has size 0, then every pointer
        // will have unknown offset with the exception that it points
        // to the begining of the memory - therefore make 0 exception
        if ((new_offset == 0 || new_offset < ptr.target->getSize())
            && new_offset < *options.fieldSensitivity)
            changed |= node->addPointsTo(ptr.target, new_offset);
        else
            changed |= node->addPointsTo(ptr.target, Offset::UNKNOWN);
    }

    return changed;
}

bool PointerAnalysis::processNode(PSNode *node)
{
    bool changed = false;
    std::vector<MemoryObject *> objects;

#ifdef DEBUG_ENABLED
    size_t prev_size = node->pointsTo.size();
#endif

    switch(node->type) {
        case PSNodeType::LOAD:
            changed |= processLoad(node);
            break;
        case PSNodeType::STORE:
            for (const Pointer& ptr : node->getOperand(1)->pointsTo) {
                assert(ptr.target && "Got nullptr as target");

                if (!canBeDereferenced(ptr))
                    continue;

                objects.clear();
                getMemoryObjects(node, ptr, objects);
                for (MemoryObject *o : objects) {
                    changed |= o->addPointsTo(ptr.offset,
                                              node->getOperand(0)->pointsTo);
                }
            }
            break;
        case PSNodeType::INVALIDATE_OBJECT:
        case PSNodeType::FREE:
            break;
        case PSNodeType::INVALIDATE_LOCALS:
            // FIXME: get rid of this type of node
            // (make the analysis extendable and move it there)
            node->setParent(node->getOperand(0)->getSingleSuccessor()->getParent());
            break;
        case PSNodeType::GEP:
            changed |= processGep(node);
            break;
        case PSNodeType::CAST:
            // cast only copies the pointers
            changed |= node->addPointsTo(node->getOperand(0)->pointsTo);
            break;
        case PSNodeType::CONSTANT:
            // maybe warn? It has no sense to insert the constants into the graph.
            // On the other hand it is harmless. We can at least check if it is
            // correctly initialized 8-)
            assert(node->pointsTo.size() == 1
                   && "Constant should have exactly one pointer");
            break;
        case PSNodeType::CALL_RETURN:
            if (options.invalidateNodes) {
                for (PSNode *op : node->operands) {
                    for (const Pointer& ptr : op->pointsTo) {
                        if (!canBeDereferenced(ptr))
                            continue;
                        PSNodeAlloc *target = PSNodeAlloc::get(ptr.target);
                        assert(target && "Target is not memory allocation");
                        if (!target->isHeap() && !target->isGlobal()) {
                            changed |= node->addPointsTo(INVALIDATED);
                        }
                    }
                }
            }
            // fall-through
        case PSNodeType::RETURN:
            // gather pointers returned from subprocedure - the same way
            // as PHI works
        case PSNodeType::PHI:
            for (PSNode *op : node->operands)
                changed |= node->addPointsTo(op->pointsTo);
            break;
        case PSNodeType::CALL_FUNCPTR:
            // call via function pointer:
            // first gather the pointers that can be used to the
            // call and if something changes, let backend take some action
            // (for example build relevant subgraph)
            for (const Pointer& ptr : node->getOperand(0)->pointsTo) {
                // do not add pointers that do not point to functions
                // (but do not do that when we are looking for invalidated
                // memory as this may lead to undefined behavior)
                if (!options.invalidateNodes
                    && ptr.target->getType() != PSNodeType::FUNCTION)
                    continue;

                if (node->addPointsTo(ptr)) {
                    changed = true;

                    if (ptr.isValid() && !ptr.isInvalidated()) {
                        if (functionPointerCall(node, ptr.target))
                            recomputeSCCs();
                    } else {
                        error(node, "Calling invalid pointer as a function!");
                        continue;
                    }
                }
            }
            break;
        case PSNodeType::MEMCPY:
            changed |= processMemcpy(node);
            break;
        case PSNodeType::ALLOC:
        case PSNodeType::DYN_ALLOC:
        case PSNodeType::FUNCTION:
            // these two always points to itself
            assert(node->doesPointsTo(node, 0));
            assert(node->pointsTo.size() == 1);
        case PSNodeType::CALL:
        case PSNodeType::ENTRY:
        case PSNodeType::NOOP:
            // just no op
            break;
        default:
            assert(0 && "Unknown type");
    }

#ifdef DEBUG_ENABLED
    // the change of points-to set is not the only
    // change that can happen, so we don't use it as an
    // indicator and we use the 'changed' variable instead.
    // However, this assertion must hold:
    assert((node->pointsTo.size() == prev_size || changed)
           && "BUG: Did not set change but changed points-to sets");
#endif

    return changed;
}

void PointerAnalysis::sanityCheck() {
#ifndef NDEBUG
    assert(NULLPTR->pointsTo.size() == 1
           && "Null has been assigned a pointer");
    assert(NULLPTR->doesPointsTo(NULLPTR)
           && "Null points to a different location");
    assert(UNKNOWN_MEMORY->pointsTo.size() == 1
           && "Unknown memory has been assigned a pointer");
    assert(UNKNOWN_MEMORY->doesPointsTo(UNKNOWN_MEMORY, Offset::UNKNOWN)
           && "Unknown memory has been assigned a pointer");
    assert(INVALIDATED->pointsTo.empty()
           && "Unknown memory has been assigned a pointer");

    auto nodes = PS->getNodes(PS->getRoot());
    std::set<unsigned> ids;
    for (auto nd : nodes) {
        assert(ids.insert(nd->getID()).second && "Duplicated node ID");

        if (nd->getType() == PSNodeType::ALLOC) {
            assert(nd->pointsTo.size() == 1
                   && "Alloc does not point only to itself");
            assert(nd->doesPointsTo(nd, 0)
                   && "Alloc does not point only to itself");
        }
    }
#endif // not NDEBUG
}

} // namespace pta
} // namespace analysis
} // namespace dg
<|endoftext|>


<commit_before>#include <cstring>
#include <iostream>

#include <UnitTest++.h>
#include <TestReporter.h> // Part of UnitTest++

#include <tightdb/utilities.hpp>

// FIXME: I suggest we enable this only if
// TIGHTDB_VISUAL_LEAK_DETECTOR is defined. It is problematic that we
// cannot run the unit tests witout installing this (and indeed
// installing it in that particular location)
/*
#if defined(_MSC_VER) && defined(_DEBUG)
#  include "C:\\Program Files (x86)\\Visual Leak Detector\\include\\vld.h"
#endif
*/

using namespace std;
using namespace UnitTest;

namespace {

struct CustomTestReporter: TestReporter {
    void ReportTestStart(TestDetails const& test)
    {
        cerr << test.filename << ":" << test.lineNumber << ": Begin " << test.testName << "\n";
    }

    void ReportFailure(TestDetails const& test, char const* failure)
    {
        cerr << test.filename << ":" << test.lineNumber << ": error: "
            "Failure in " << test.testName << ": " << failure << "\n";
    }

    void ReportTestFinish(TestDetails const& test, float seconds_elapsed)
    {
        static_cast<void>(test);
        static_cast<void>(seconds_elapsed);
//        cerr << test.filename << ":" << test.lineNumber << ": End\n";
    }

    void ReportSummary(int total_test_count, int failed_test_count, int failure_count, float seconds_elapsed)
    {
        if (0 < failure_count)
            cerr << "FAILURE: " << failed_test_count << " "
                "out of " << total_test_count << " tests failed "
                "(" << failure_count << " failures).\n";
        else
            cerr << "Success: " << total_test_count << " tests passed.\n";

        const streamsize orig_prec = cerr.precision();
        cerr.precision(2);
        cerr << "Test time: " << seconds_elapsed << " seconds.\n";
        cerr.precision(orig_prec);
    }
};

} // anonymous namespace

int main(int argc, char* argv[])
{
    bool const no_error_exit_staus = 2 <= argc && strcmp(argv[1], "--no-error-exit-staus") == 0;

#ifdef TIGHTDB_DEBUG
    cerr << "Running Debug unit tests\n";
#else
    cerr << "Running Release unit tests\n";
#endif

    cerr << "MAX_LIST_SIZE = " << MAX_LIST_SIZE << "\n";

#ifdef TIGHTDB_COMPILER_SSE
    cerr << "Compiler supported SSE (auto detect): Yes\n";
#else
    cerr << "Compiler supported SSE (auto detect): No\n";
#endif

    cerr << "This CPU supports SSE (auto detect):  " << (tightdb::cpuid_sse<42>() ? "4.2" : (tightdb::cpuid_sse<30>() ? "3.0" : "None"));
    cerr << "\n\n";

    CustomTestReporter reporter;
    TestRunner runner(reporter);
    const int res = runner.RunTestsIf(Test::GetTestList(), 0, True(), 0);

#ifdef _MSC_VER
    getchar(); // wait for key
#endif
    return no_error_exit_staus ? 0 : res;
}
<commit_msg>Disable reporting of unit test names as they run<commit_after>#include <cstring>
#include <iostream>

#include <UnitTest++.h>
#include <TestReporter.h> // Part of UnitTest++

#include <tightdb/utilities.hpp>

// FIXME: I suggest we enable this only if
// TIGHTDB_VISUAL_LEAK_DETECTOR is defined. It is problematic that we
// cannot run the unit tests witout installing this (and indeed
// installing it in that particular location)
/*
#if defined(_MSC_VER) && defined(_DEBUG)
#  include "C:\\Program Files (x86)\\Visual Leak Detector\\include\\vld.h"
#endif
*/

using namespace std;
using namespace UnitTest;

namespace {

struct CustomTestReporter: TestReporter {
    void ReportTestStart(TestDetails const& test)
    {
        static_cast<void>(test);
//        cerr << test.filename << ":" << test.lineNumber << ": Begin " << test.testName << "\n";
    }

    void ReportFailure(TestDetails const& test, char const* failure)
    {
        cerr << test.filename << ":" << test.lineNumber << ": error: "
            "Failure in " << test.testName << ": " << failure << "\n";
    }

    void ReportTestFinish(TestDetails const& test, float seconds_elapsed)
    {
        static_cast<void>(test);
        static_cast<void>(seconds_elapsed);
//        cerr << test.filename << ":" << test.lineNumber << ": End\n";
    }

    void ReportSummary(int total_test_count, int failed_test_count, int failure_count, float seconds_elapsed)
    {
        if (0 < failure_count)
            cerr << "FAILURE: " << failed_test_count << " "
                "out of " << total_test_count << " tests failed "
                "(" << failure_count << " failures).\n";
        else
            cerr << "Success: " << total_test_count << " tests passed.\n";

        const streamsize orig_prec = cerr.precision();
        cerr.precision(2);
        cerr << "Test time: " << seconds_elapsed << " seconds.\n";
        cerr.precision(orig_prec);
    }
};

} // anonymous namespace

int main(int argc, char* argv[])
{
    bool const no_error_exit_staus = 2 <= argc && strcmp(argv[1], "--no-error-exit-staus") == 0;

#ifdef TIGHTDB_DEBUG
    cerr << "Running Debug unit tests\n";
#else
    cerr << "Running Release unit tests\n";
#endif

    cerr << "MAX_LIST_SIZE = " << MAX_LIST_SIZE << "\n";

#ifdef TIGHTDB_COMPILER_SSE
    cerr << "Compiler supported SSE (auto detect): Yes\n";
#else
    cerr << "Compiler supported SSE (auto detect): No\n";
#endif

    cerr << "This CPU supports SSE (auto detect):  " << (tightdb::cpuid_sse<42>() ? "4.2" : (tightdb::cpuid_sse<30>() ? "3.0" : "None"));
    cerr << "\n\n";

    CustomTestReporter reporter;
    TestRunner runner(reporter);
    const int res = runner.RunTestsIf(Test::GetTestList(), 0, True(), 0);

#ifdef _MSC_VER
    getchar(); // wait for key
#endif
    return no_error_exit_staus ? 0 : res;
}
<|endoftext|>


<commit_before>#include "stdafx.h"

BDD representState(Cudd manager, std::vector<bool> values) {
    BDD bdd = manager.bddOne();
    int i = 0;
    for (auto it = std::begin(values); it != std::end(values); ++it) {
        BDD var = manager.bddVar(i);
        if (!*it) {
            var = !var;
        }
        bdd = var * bdd;
        i++;
    }
    return bdd;
}

BDD representCnf(Cudd manager, std::vector<int> cnf) {
    BDD bdd = manager.bddZero();
    for (auto it = std::begin(cnf); it != std::end(cnf); ++it) {
        BDD var = manager.bddVar(abs(*it));
        if (*it < 0) {
            var = !var;
        }
        bdd = var + bdd;
    }
    return bdd;
}

BDD representUpdateFunction(Cudd manager, std::vector<std::vector<int>> cnfs) {
    BDD bdd = manager.bddOne();
    for (auto it = std::begin(cnfs); it != std::end(cnfs); ++it) {
        bdd = bdd * representCnf(manager, *it);
    }
    return bdd;
}

BDD logicalEquivalence(BDD a, BDD b) {
    return (a * b) + ((!a) * (!b));
}

BDD representSyncTransitionRelation(Cudd manager, std::vector<std::vector<std::vector<int>>> network) {
    BDD bdd = manager.bddOne();
    int i = 0;
    for (auto it = std::begin(network); it != std::end(network); ++it) {
        BDD f = representUpdateFunction(manager, *it);
        BDD vPrime = manager.bddVar(network.size() + i);
        BDD transition = logicalEquivalence(vPrime, f);
        bdd = transition * bdd;
        i++;
    }
    return bdd;
}

BDD otherVarsDoNotChange(Cudd manager, int i, int numVars) {
    BDD bdd = manager.bddOne();
    for (int j = 0; j < numVars; j++) {
        if (j != i) {
            BDD v = manager.bddVar(j);
            BDD vPrime = manager.bddVar(numVars + j);
            bdd = bdd * logicalEquivalence(v, vPrime);
        }
    }
    return bdd;
}

BDD representAsyncTransitionRelation(Cudd manager, std::vector<std::vector<std::vector<int>>> network) {
    BDD fixpoint = manager.bddOne();
    for (int i = 0; i < network.size(); i++) {
        BDD v = manager.bddVar(i);
        BDD vPrime = manager.bddVar(network.size() + i);
        fixpoint = fixpoint * logicalEquivalence(v, vPrime);
    }

    BDD bdd = manager.bddZero();
    int i = 0;
    for (auto it = std::begin(network); it != std::end(network); ++it) {
        BDD v = manager.bddVar(i);
        BDD vPrime = manager.bddVar(network.size() + i);
        BDD vChanges = !logicalEquivalence(v, vPrime);
        BDD f = representUpdateFunction(manager, *it);
        BDD update = logicalEquivalence(vPrime, f) * otherVarsDoNotChange(manager, i, network.size());
        BDD transition = update * (fixpoint + vChanges);
        bdd = transition + bdd;
        i++;
    }

    return bdd;
}

BDD renameRemovingPrimes(BDD bdd, int numVars) {
    int *permute = new int[numVars * 2];
    for (int i = 0; i < numVars; i++) {
        permute[i] = i;
        permute[i + numVars] = i;
    }
    BDD r = bdd.Permute(permute);
    delete[] permute;
    return r;
}

BDD nonPrimeVariables(Cudd manager, int numVars) {
    return representState(manager, std::vector<bool>(numVars, true));
}

BDD primeVariables(Cudd manager, int numVars) {
    BDD bdd = manager.bddOne();
    for (int i = numVars; i < numVars * 2; i++) {
        BDD var = manager.bddVar(i);
        bdd = var * bdd;
    }
    return bdd;
}

BDD immediateSuccessorStates(Cudd manager, BDD transitionBdd, BDD valuesBdd, int numVars) {
    BDD bdd = transitionBdd * valuesBdd;
    bdd = bdd.ExistAbstract(nonPrimeVariables(manager, numVars));
    bdd = renameRemovingPrimes(bdd, numVars);
    return bdd;
}

BDD forwardReachableStates(Cudd manager, BDD transitionBdd, BDD valuesBdd, int numVars) {
    BDD reachable = manager.bddZero();
    BDD frontier = valuesBdd;

    while (frontier != manager.bddZero()) {
        frontier = immediateSuccessorStates(manager, transitionBdd, frontier, numVars) * !reachable;
        reachable = reachable + frontier;
    }
    return reachable;
}

BDD renameAddingPrimes(BDD bdd, int numVars) {
    int *permute = new int[numVars * 2];
    for (int i = 0; i < numVars; i++) {
        permute[i] = i + numVars;
        permute[i + numVars] = i + numVars;
    }

    BDD r = bdd.Permute(permute);
    delete[] permute;
    return r;
}

BDD immediatePredecessorStates(Cudd manager, BDD transitionBdd, BDD valuesBdd, int numVars) {
    valuesBdd = renameAddingPrimes(valuesBdd, numVars);
    BDD bdd = transitionBdd * valuesBdd;
    bdd = bdd.ExistAbstract(primeVariables(manager, numVars));
    return bdd;
}

BDD backwardReachableStates(Cudd manager, BDD transitionBdd, BDD valuesBdd, int numVars) {
    BDD reachable = manager.bddZero();
    BDD frontier = valuesBdd;

    while (frontier != manager.bddZero()) {
        frontier = immediatePredecessorStates(manager, transitionBdd, frontier, numVars) * !reachable;
        reachable = reachable + frontier;
    }
    return reachable;
}

BDD randomState(Cudd manager, BDD S, int numVars) {
    char *out = new char[numVars * 2];
    S.PickOneCube(out);

    std::vector<bool> values;
    for (int i = 0; i < numVars; i++) {
        if (out[i] == 0) {
            values.push_back(false);
        }
        else {
            values.push_back(true);
        }
    }

    delete[] out;
    return representState(manager, values);
}

std::vector<BDD> attractors(Cudd manager, BDD transitionBdd, int numVars) {
    std::vector<BDD> attractors = std::vector<BDD>();
    BDD S = manager.bddOne();
    while (S != manager.bddZero()) {
        BDD s = randomState(manager, S, numVars);
        BDD fr = forwardReachableStates(manager, transitionBdd, s, numVars);
        BDD br = backwardReachableStates(manager, transitionBdd, s, numVars);

        if ((fr * !br) == manager.bddZero()) {
            attractors.push_back(fr);
        }

        S = S * !(s + br);
    }
    return attractors;
}

int main() {
    //Cebpa, Pu.1, Gata2, Gata1, Fog1, EKLF, Fli1, Scl, cJun, EgrNab, Gfi1
    std::vector<bool> cmpInitial = { true, true, true, false, false, false, false, false, false, false, false };
    std::vector<std::vector<int>> cebpa = { { 0 },{ -7 },{ -3, -4 } };
    std::vector<std::vector<int>> pu1 = { { 0, 1 },{ -2 },{ -3 } };
    std::vector<std::vector<int>> gata2 = { { 3 },{ -1 },{ -3, -4 } };
    std::vector<std::vector<int>> gata1 = { { 2, 3, 6 },{ -1 } };
    std::vector<std::vector<int>> fog1 = { { 3 } };
    std::vector<std::vector<int>> eklf = { { 3 },{ -6 } };
    std::vector<std::vector<int>> fli1 = { { 3 },{ -5 } };
    std::vector<std::vector<int>> scl = { { 3 },{ -1 } };
    std::vector<std::vector<int>> cJun = { { 1 },{ -10 } };
    std::vector<std::vector<int>> egrNab = { { 1 },{ 8 },{ -10 } };
    std::vector<std::vector<int>> gfi1 = { { 0 },{ -9 } };
    std::vector<std::vector<std::vector<int>>> cmp = { cebpa, pu1, gata2, gata1, fog1, eklf, fli1, scl, cJun, egrNab, gfi1 };

    Cudd manager(0, 0);
    BDD initialStateBdd = representState(manager, cmpInitial);

    BDD transitionBddA = representAsyncTransitionRelation(manager, cmp);
    BDD statespace = forwardReachableStates(manager, transitionBddA, initialStateBdd, cmpInitial.size());
    std::cout << statespace.CountMinterm(cmpInitial.size());
    std::cout << "\n";

    std::vector<BDD> attsA = attractors(manager, transitionBddA, cmpInitial.size());
    for (BDD attractor : attsA) {
        attractor.PrintMinterm();
        std::cout << "\n";
    }

    std::cout << "--------------------------------\n";

    BDD transitionBddS = representSyncTransitionRelation(manager, cmp);
    std::vector<BDD> attsS = attractors(manager, transitionBddS, cmpInitial.size());
    for (BDD attractor : attsS) {
        attractor.PrintMinterm();
        std::cout << "\n";
    }

    return 0;
}
<commit_msg>Minor syntax changes<commit_after>#include "stdafx.h"

BDD representState(Cudd manager, std::vector<bool> values) {
    BDD bdd = manager.bddOne();
    int i = 0;
    for (auto it = std::begin(values); it != std::end(values); ++it) {
        BDD var = manager.bddVar(i);
        if (!*it) {
            var = !var;
        }
        bdd = var * bdd;
        i++;
    }
    return bdd;
}

BDD representCnf(Cudd manager, std::vector<int> cnf) {
    BDD bdd = manager.bddZero();
    for (auto it = std::begin(cnf); it != std::end(cnf); ++it) {
        BDD var = manager.bddVar(abs(*it));
        if (*it < 0) {
            var = !var;
        }
        bdd = var + bdd;
    }
    return bdd;
}

BDD representUpdateFunction(Cudd manager, std::vector<std::vector<int>> cnfs) {
    BDD bdd = manager.bddOne();
    for (auto it = std::begin(cnfs); it != std::end(cnfs); ++it) {
        bdd = bdd * representCnf(manager, *it);
    }
    return bdd;
}

BDD logicalEquivalence(BDD a, BDD b) {
    return (a * b) + ((!a) * (!b));
}

BDD representSyncTransitionRelation(Cudd manager, std::vector<std::vector<std::vector<int>>> network) {
    BDD bdd = manager.bddOne();
    int i = 0;
    for (auto it = std::begin(network); it != std::end(network); ++it) {
        BDD f = representUpdateFunction(manager, *it);
        BDD vPrime = manager.bddVar(network.size() + i);
        BDD transition = logicalEquivalence(vPrime, f);
        bdd = transition * bdd;
        i++;
    }
    return bdd;
}

BDD otherVarsDoNotChange(Cudd manager, int i, int numVars) {
    BDD bdd = manager.bddOne();
    for (int j = 0; j < numVars; j++) {
        if (j != i) {
            BDD v = manager.bddVar(j);
            BDD vPrime = manager.bddVar(numVars + j);
            bdd = bdd * logicalEquivalence(v, vPrime);
        }
    }
    return bdd;
}

BDD representAsyncTransitionRelation(Cudd manager, std::vector<std::vector<std::vector<int>>> network) {
    BDD fixpoint = manager.bddOne();
    for (int i = 0; i < network.size(); i++) {
        BDD v = manager.bddVar(i);
        BDD vPrime = manager.bddVar(network.size() + i);
        fixpoint = fixpoint * logicalEquivalence(v, vPrime);
    }

    BDD bdd = manager.bddZero();
    int i = 0;
    for (auto it = std::begin(network); it != std::end(network); ++it) {
        BDD v = manager.bddVar(i);
        BDD vPrime = manager.bddVar(network.size() + i);
        BDD vChanges = !logicalEquivalence(v, vPrime);
        BDD f = representUpdateFunction(manager, *it);
        BDD update = logicalEquivalence(vPrime, f) * otherVarsDoNotChange(manager, i, network.size());
        BDD transition = update * (fixpoint + vChanges);
        bdd = transition + bdd;
        i++;
    }

    return bdd;
}

BDD renameRemovingPrimes(BDD bdd, int numVars) {
    int *permute = new int[numVars * 2];
    for (int i = 0; i < numVars; i++) {
        permute[i] = i;
        permute[i + numVars] = i;
    }
    BDD r = bdd.Permute(permute);
    delete[] permute;
    return r;
}

BDD nonPrimeVariables(Cudd manager, int numVars) {
    return representState(manager, std::vector<bool>(numVars, true));
}

BDD primeVariables(Cudd manager, int numVars) {
    BDD bdd = manager.bddOne();
    for (int i = numVars; i < numVars * 2; i++) {
        BDD var = manager.bddVar(i);
        bdd = var * bdd;
    }
    return bdd;
}

BDD immediateSuccessorStates(Cudd manager, BDD transitionBdd, BDD valuesBdd, int numVars) {
    BDD bdd = transitionBdd * valuesBdd;
    bdd = bdd.ExistAbstract(nonPrimeVariables(manager, numVars));
    bdd = renameRemovingPrimes(bdd, numVars);
    return bdd;
}

BDD forwardReachableStates(Cudd manager, BDD transitionBdd, BDD valuesBdd, int numVars) {
    BDD reachable = manager.bddZero();
    BDD frontier = valuesBdd;

    while (frontier != manager.bddZero()) {
        frontier = immediateSuccessorStates(manager, transitionBdd, frontier, numVars) * !reachable;
        reachable = reachable + frontier;
    }
    return reachable;
}

BDD renameAddingPrimes(BDD bdd, int numVars) {
    int *permute = new int[numVars * 2];
    for (int i = 0; i < numVars; i++) {
        permute[i] = i + numVars;
        permute[i + numVars] = i + numVars;
    }

    BDD r = bdd.Permute(permute);
    delete[] permute;
    return r;
}

BDD immediatePredecessorStates(Cudd manager, BDD transitionBdd, BDD valuesBdd, int numVars) {
    valuesBdd = renameAddingPrimes(valuesBdd, numVars);
    BDD bdd = transitionBdd * valuesBdd;
    bdd = bdd.ExistAbstract(primeVariables(manager, numVars));
    return bdd;
}

BDD backwardReachableStates(Cudd manager, BDD transitionBdd, BDD valuesBdd, int numVars) {
    BDD reachable = manager.bddZero();
    BDD frontier = valuesBdd;

    while (frontier != manager.bddZero()) {
        frontier = immediatePredecessorStates(manager, transitionBdd, frontier, numVars) * !reachable;
        reachable = reachable + frontier;
    }
    return reachable;
}

BDD randomState(Cudd manager, BDD S, int numVars) {
    char *out = new char[numVars * 2];
    S.PickOneCube(out);

    std::vector<bool> values;
    for (int i = 0; i < numVars; i++) {
        if (out[i] == 0) {
            values.push_back(false);
        }
        else {
            values.push_back(true);
        }
    }

    delete[] out;
    return representState(manager, values);
}

std::vector<BDD> attractors(Cudd manager, BDD transitionBdd, int numVars) {
    std::vector<BDD> attractors = std::vector<BDD>();
    BDD S = manager.bddOne();
    while (S != manager.bddZero()) {
        BDD s = randomState(manager, S, numVars);
        BDD fr = forwardReachableStates(manager, transitionBdd, s, numVars);
        BDD br = backwardReachableStates(manager, transitionBdd, s, numVars);

        if ((fr * !br) == manager.bddZero()) {
            attractors.push_back(fr);
        }

        S = S * !(s + br);
    }
    return attractors;
}

int main() {
    //Cebpa, Pu.1, Gata2, Gata1, Fog1, EKLF, Fli1, Scl, cJun, EgrNab, Gfi1
    std::vector<bool> cmpInitial { true, true, true, false, false, false, false, false, false, false, false };
    std::vector<std::vector<int>> cebpa { { 0 },{ -7 },{ -3, -4 } };
    std::vector<std::vector<int>> pu1 { { 0, 1 },{ -2 },{ -3 } };
    std::vector<std::vector<int>> gata2 { { 3 },{ -1 },{ -3, -4 } };
    std::vector<std::vector<int>> gata1 { { 2, 3, 6 },{ -1 } };
    std::vector<std::vector<int>> fog1 { { 3 } };
    std::vector<std::vector<int>> eklf { { 3 },{ -6 } };
    std::vector<std::vector<int>> fli1 { { 3 },{ -5 } };
    std::vector<std::vector<int>> scl { { 3 },{ -1 } };
    std::vector<std::vector<int>> cJun { { 1 },{ -10 } };
    std::vector<std::vector<int>> egrNab { { 1 },{ 8 },{ -10 } };
    std::vector<std::vector<int>> gfi1 { { 0 },{ -9 } };
    std::vector<std::vector<std::vector<int>>> cmp { cebpa, pu1, gata2, gata1, fog1, eklf, fli1, scl, cJun, egrNab, gfi1 };

    Cudd manager(0, 0);
    BDD initialStateBdd = representState(manager, cmpInitial);

    BDD transitionBddA = representAsyncTransitionRelation(manager, cmp);
    BDD statespace = forwardReachableStates(manager, transitionBddA, initialStateBdd, cmpInitial.size());
    std::cout << statespace.CountMinterm(cmpInitial.size());
    std::cout << "\n";

    std::vector<BDD> attsA = attractors(manager, transitionBddA, cmpInitial.size());
    for (BDD attractor : attsA) {
        attractor.PrintMinterm();
        std::cout << "\n";
    }

    std::cout << "--------------------------------\n";

    BDD transitionBddS = representSyncTransitionRelation(manager, cmp);
    std::vector<BDD> attsS = attractors(manager, transitionBddS, cmpInitial.size());
    for (BDD attractor : attsS) {
        attractor.PrintMinterm();
        std::cout << "\n";
    }

    return 0;
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_META_PROMOTE_VAR_MATRIX
#define STAN_MATH_REV_META_PROMOTE_VAR_MATRIX

#include <stan/math/rev/meta/is_var.hpp>
#include <stan/math/prim/meta.hpp>

namespace stan {
  template <typename ReturnType, typename... Types>
  using promote_var_matrix_t = std::conditional_t<is_any_var_matrix<Types...>::value,
    stan::math::var_value<stan::math::promote_scalar_t<double, plain_type_t<ReturnType>>>,
     stan::math::promote_scalar_t<stan::math::var, plain_type_t<ReturnType>>>;
}

#endif
<commit_msg>fix includes<commit_after>#ifndef STAN_MATH_REV_META_PROMOTE_VAR_MATRIX
#define STAN_MATH_REV_META_PROMOTE_VAR_MATRIX

#include <stan/math/rev/meta/is_var.hpp>
#include <stan/math/rev/core/var.hpp>
#include <stan/math/prim/meta.hpp>

namespace stan {
  template <typename ReturnType, typename... Types>
  using promote_var_matrix_t = std::conditional_t<is_any_var_matrix<Types...>::value,
    stan::math::var_value<stan::math::promote_scalar_t<double, plain_type_t<ReturnType>>>,
     stan::math::promote_scalar_t<stan::math::var, plain_type_t<ReturnType>>>;
}

#endif
<|endoftext|>


<commit_before>#include "mex.h"
#include "matrix.h"

#include <math.h>

#include <iostream>
using std::cout;
using std::endl;

#include <sstream>
using std::ostringstream;

#include <string>
using std::string;

#include <tr1/functional>
#include <tr1/unordered_map>
using std::tr1::hash;
using std::tr1::unordered_map;

extern "C" {
#include <cblas.h>
}

/* convenience macros for input/output indices in case we want to change */
#define A_ARG               prhs[0]
#define LABELS_ARG          prhs[1]
#define GRAPH_IND_ARG       prhs[2]
#define H_ARG               prhs[3]

#define KERNEL_MATRIX_ARG   plhs[0]

#define INDEX(row, column, num_rows) ((int)(row) + ((int)(num_rows) * (int)(column)))

void mexFunction(int nlhs, mxArray *plhs[],
								 int nrhs, const mxArray *prhs[])
{
	mwIndex *A_ir, *A_jc;
	double *graph_ind, *labels_in, *h_in, *kernel_matrix;
	int h, *labels;

	int i, j, k, row, column, count, offset, iteration, num_nodes, num_labels, num_new_labels, num_graphs,
		num_elements_this_column, index, *counts;

	double *feature_vectors;

	unordered_map<string, int, hash<string> > signature_hash;

	A_ir      = mxGetIr(A_ARG);
	A_jc      = mxGetJc(A_ARG);

	labels_in = mxGetPr(LABELS_ARG);

	graph_ind = mxGetPr(GRAPH_IND_ARG);
	h_in      = mxGetPr(H_ARG);

	/* dereference to avoid annoying casting and indexing */
	h = (int)(h_in[0] + 0.5);

	num_nodes = mxGetN(A_ARG);

	/* copy label matrix because we will overwrite it */
	labels = new int[num_nodes];
	for (i = 0; i < num_nodes; i++)
		labels[i] = (int)(labels_in[i] + 0.5);

	num_labels = 0;
	num_graphs = 0;
	for (i = 0; i < num_nodes; i++) {
		if (labels[i] > num_labels)
			num_labels = (int)(labels[i]);
		if ((int)(graph_ind[i]) > num_graphs)
			num_graphs = (int)(graph_ind[i] + 0.5);
	}

	KERNEL_MATRIX_ARG = mxCreateDoubleMatrix(num_graphs, num_graphs, mxREAL);
	kernel_matrix = mxGetPr(KERNEL_MATRIX_ARG);

	feature_vectors = NULL;
	counts          = NULL;

	iteration = 0;
	while (true) {

		delete[] feature_vectors;
		feature_vectors = new double[num_graphs * num_labels]();

		for (i = 0; i < num_nodes; i++)
			feature_vectors[INDEX(graph_ind[i] - 1, labels[i] - 1, num_graphs)]++;

		cblas_dsyrk(CblasColMajor, CblasUpper, CblasNoTrans, num_graphs, num_labels,
		 						1.0, feature_vectors, num_graphs, 1.0, kernel_matrix, num_graphs);

		if (iteration == h)
			break;

		delete[] counts;
		counts = new int[num_nodes * num_labels];
		for (i = 0; i < num_nodes * num_labels; i++)
			counts[i] = 0;

 		count = 0;
		for (column = 0; column < num_nodes; column++) {
			num_elements_this_column = A_jc[column + 1] - A_jc[column];
			for (i = 0; i < num_elements_this_column; i++, count++) {
				row = A_ir[count];
				counts[INDEX(row, labels[column] - 1, num_nodes)]++;
			}
		}

		num_new_labels = 0;
		for (i = 0; i < num_nodes; i++) {
			ostringstream signature;
			signature << labels[i];

			for (j = 0; j < num_labels; j++)
				if (counts[INDEX(i, j, num_nodes)])
					signature << " " << j << " " << counts[INDEX(i, j, num_nodes)];

			if (signature_hash.count(signature.str()) == 0) {
				num_new_labels++;
				labels[i] = num_new_labels;
				signature_hash[signature.str()] = num_labels;
			}
			else
				labels[i] = signature_hash[signature.str()];
		}
		signature_hash.clear();

		num_labels = num_new_labels;
		iteration++;
	}

	delete[] labels;
	delete[] feature_vectors;
	delete[] counts;
}
<commit_msg>running inline<commit_after>#include "mex.h"
#include "matrix.h"

#include <math.h>
#include <string.h>

#include <iostream>
using std::cout;
using std::endl;

#include <sstream>
using std::ostringstream;

#include <string>
using std::string;

#include <tr1/functional>
#include <tr1/unordered_map>
using std::tr1::hash;
using std::tr1::unordered_map;

extern "C" {
#include <cblas.h>
}

/* convenience macros for input/output indices in case we want to change */
#define A_ARG               prhs[0]
#define LABELS_ARG          prhs[1]
#define GRAPH_IND_ARG       prhs[2]
#define H_ARG               prhs[3]

#define KERNEL_MATRIX_ARG   plhs[0]

#define INDEX(row, column, num_rows) ((int)(row) + ((int)(num_rows) * (int)(column)))

void mexFunction(int nlhs, mxArray *plhs[],
								 int nrhs, const mxArray *prhs[])
{
	mwIndex *A_ir, *A_jc;
	double *graph_ind, *labels_in, *h_in, *kernel_matrix;
	int h, *labels, *new_labels;

	int i, j, k, count, iteration;
	int num_nodes, num_labels, num_new_labels, num_graphs, num_neighbors, *counts;

	double *feature_vectors;

	unordered_map<string, int, hash<string> > signature_hash;

	A_ir      = mxGetIr(A_ARG);
	A_jc      = mxGetJc(A_ARG);

	labels_in = mxGetPr(LABELS_ARG);

	graph_ind = mxGetPr(GRAPH_IND_ARG);
	h_in      = mxGetPr(H_ARG);

	/* dereference to avoid annoying casting and indexing */
	h = (int)(h_in[0] + 0.5);

	num_nodes = mxGetN(A_ARG);

	/* copy label matrix because we will overwrite it */
	labels = new int[num_nodes];
	for (i = 0; i < num_nodes; i++)
		labels[i] = (int)(labels_in[i] + 0.5);

	num_labels = 0;
	num_graphs = 0;
	for (i = 0; i < num_nodes; i++) {
		if (labels[i] > num_labels)
			num_labels = (int)(labels[i]);
		if ((int)(graph_ind[i]) > num_graphs)
			num_graphs = (int)(graph_ind[i] + 0.5);
	}

	KERNEL_MATRIX_ARG = mxCreateDoubleMatrix(num_graphs, num_graphs, mxREAL);
	kernel_matrix = mxGetPr(KERNEL_MATRIX_ARG);

	feature_vectors = NULL;
	counts          = NULL;
	new_labels      = new int[num_nodes];

	iteration = 0;
	while (true) {

		delete[] feature_vectors;
		feature_vectors = new double[num_graphs * num_labels]();

		for (i = 0; i < num_nodes; i++)
			feature_vectors[INDEX(graph_ind[i] - 1, labels[i] - 1, num_graphs)]++;

		cblas_dsyrk(CblasColMajor, CblasUpper, CblasNoTrans, num_graphs, num_labels,
		 						1.0, feature_vectors, num_graphs, 1.0, kernel_matrix, num_graphs);

		if (iteration == h)
			break;

		delete[] counts;
		counts = new int[num_labels];

		num_new_labels = 0;
		count = 0;
		for (i = 0; i < num_nodes; i++) {

			for (j = 0; j < num_labels; j++)
				counts[j] = 0;

			num_neighbors = A_jc[i + 1] - A_jc[i];
			for (j = 0; j < num_neighbors; j++, count++)
				counts[labels[A_ir[count]] - 1]++;

			ostringstream signature;
			signature << labels[i];

			for (j = 0; j < num_labels; j++)
				signature << " " << j << " " << counts[j];

			if (signature_hash.count(signature.str()) == 0) {
				num_new_labels++;
				new_labels[i] = num_new_labels;
				signature_hash[signature.str()] = num_new_labels;
			}
			else
				new_labels[i] = signature_hash[signature.str()];
		}
		signature_hash.clear();

		num_labels = num_new_labels;
		memcpy(new_labels, labels, num_nodes * sizeof(int));

		iteration++;
	}

	delete[] labels;
	delete[] feature_vectors;
	delete[] counts;
}
<|endoftext|>


<commit_before>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

Bohrium is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.

Bohrium is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <string>
#include <cstring>
#include <bh.h>
#include "bh_fuse.h"
#include "bh_fuse_cache.h"
#include <fstream>
#include <exception>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/version.hpp>
#include <boost/algorithm/string/predicate.hpp> //For iequals()

using namespace std;
using namespace boost;
using namespace boost::filesystem;

namespace bohrium {

/* * OBS * OBS * OBS * OBS * OBS * OBS * OBS * OBS * OBS * OBS * OBS * OBS
 * When designing an instruction hash function REMEMBER:
 * The hash string should either be of fixed length and all feilds
 * contained also be of fixed legth OR unique seperators should be
 * used for each variable length field and to seperate instruction
 * hashed. The function hashOpcodeIdShapeSweepdim may be used as
 * inspiration.
 */

static const size_t inst_sep = SIZE_MAX;
static const size_t op_sep   = SIZE_MAX-1;

static void hashOpcodeOpidShapeidSweepdim(std::ostream& os, const bh_instruction& instr,
                                        BatchHash& batchHash)
{
    /* The Instruction hash consists of the following fields:
     * <opcode> (<operant-id> <ndim> <shape> <op_sep>)[1] <sweep-dim>[2] <inst_sep>
     * 1: for each operand
     * 2: if the operation is a sweep operation
     */
    int noperands = bh_operands(instr.opcode);
    os.write((const char*)&instr.opcode, sizeof(instr.opcode));         // <opcode>
    for(int oidx=0; oidx<noperands; ++oidx) {
        const bh_view& view = instr.operand[oidx];
        if (bh_is_constant(&view))
            continue;  // Ignore constants
        std::pair<size_t,bool> vid = batchHash.views.insert(view);
        size_t id = vid.first;
        os.write((char*)&id, sizeof(id));                               // <operant-id>
        os.write((char*)&view.ndim, sizeof(view.ndim));                 // <ndim>
        std::pair<size_t,bool> sidp = batchHash.shapes.insert(std::vector<bh_index>(view.shape,view.shape+view.ndim));
        os.write((char*)&sidp.first, sizeof(sidp.first));                   // <shape-id>
        os.write((char*)&op_sep, sizeof(op_sep));                       // <op_sep>
    }
    if (bh_opcode_is_sweep(instr.opcode))
        os.write((char*)&instr.constant.value.int64, sizeof(bh_int64)); // <sweep-dim>
    os.write((char*)&inst_sep, sizeof(inst_sep));                       // <inst_sep>
}

static void hashOpidSweepdim(std::ostream& os, const bh_instruction& instr, BatchHash& batchHash)
{
    /* The Instruction hash consists of the following fields:
     * (<operant-id>)[1] <op_sep> (<ndim> <sweep-dim>)[2] <seperator>
     * 1: for each operand
     * 2: if the operation is a sweep operation
     */
    int noperands = bh_operands(instr.opcode);
    for(int oidx=0; oidx<noperands; ++oidx) {
        const bh_view& view = instr.operand[oidx];
        if (bh_is_constant(&view))
            continue;  // Ignore constants
        std::pair<size_t,bool> vid = batchHash.views.insert(view);
        size_t id = vid.first;
        os.write((char*)&id, sizeof(id));                               // <operant-id>
    }
    os.write((char*)&op_sep, sizeof(op_sep));                           // <op_sep>
    if (bh_opcode_is_sweep(instr.opcode))
    {
        const bh_view& view = instr.operand[1];
        os.write((char*)&view.ndim, sizeof(view.ndim));                 // <ndim>
        os.write((char*)&instr.constant.value.int64, sizeof(bh_int64)); // <sweep-dim>
    }
    os.write((char*)&inst_sep, sizeof(inst_sep));                       // <inst_sep>
}

static void hashScalarOpidSweepdim(std::ostream& os, const bh_instruction& instr, BatchHash& batchHash)
{
    /* The Instruction hash consists of the following fields:
     * <is_scalar> (<operant-id>)[1] <op_sep> (<ndim> <sweep-dim>)[2] <seperator>
     * 1: for each operand
     * 2: if the operation is a sweep operation
     */
    bool scalar = (bh_is_scalar(&(instr.operand[0])) ||
                   (bh_opcode_is_accumulate(instr.opcode) && instr.operand[0].ndim == 1));
    os.write((char*)&scalar, sizeof(scalar));                           // <is_scalar>
    int noperands = bh_operands(instr.opcode);
    for(int oidx=0; oidx<noperands; ++oidx) {
        const bh_view& view = instr.operand[oidx];
        if (bh_is_constant(&view))
            continue;  // Ignore constants
        std::pair<size_t,bool> vid = batchHash.views.insert(view);
        size_t id = vid.first;
        os.write((char*)&id, sizeof(id));                               // <operant-id>
    }
    os.write((char*)&op_sep, sizeof(op_sep));                           // <op_sep>
    if (bh_opcode_is_sweep(instr.opcode))
    {
        const bh_view& view = instr.operand[1];
        os.write((char*)&view.ndim, sizeof(view.ndim));                 // <ndim>
        os.write((char*)&instr.constant.value.int64, sizeof(bh_int64)); // <sweep-dim>
    }
    os.write((char*)&inst_sep, sizeof(inst_sep));                       // <inst_sep>
}

static void hashScalarShapeidOpidSweepdim(std::ostream& os, const bh_instruction& instr, BatchHash& batchHash)
{
    /* The Instruction hash consists of the following fields:
     * <is_scalar> <shape-id> (<operant-id>)[1] <op_sep> (<ndim> <sweep-dim>)[2] <seperator>
     * 1: for each operand
     * 2: if the operation is a sweep operation
     */
    bool scalar = (bh_is_scalar(&(instr.operand[0])) ||
                   (bh_opcode_is_accumulate(instr.opcode) && instr.operand[0].ndim == 1));
    os.write((char*)&scalar, sizeof(scalar));                           // <is_scalar>
    const bh_view& view = (bh_opcode_is_sweep(instr.opcode) ? instr.operand[1] : instr.operand[0]);
    std::pair<size_t,bool> sidp = batchHash.shapes.insert(std::vector<bh_index>(view.shape,view.shape+view.ndim));
    os.write((char*)&sidp.first, sizeof(sidp.first));                   // <shape-id>
    int noperands = bh_operands(instr.opcode);
    for(int oidx=0; oidx<noperands; ++oidx) {
        const bh_view& view = instr.operand[oidx];
        if (bh_is_constant(&view))
            continue;  // Ignore constants
        std::pair<size_t,bool> vid = batchHash.views.insert(view);
        size_t id = vid.first;
        os.write((char*)&id, sizeof(id));                               // <operant-id>
    }
    os.write((char*)&op_sep, sizeof(op_sep));                           // <op_sep>
    if (bh_opcode_is_sweep(instr.opcode))
    {
        const bh_view& view = instr.operand[1];
        os.write((char*)&view.ndim, sizeof(view.ndim));                 // <ndim>
        os.write((char*)&instr.constant.value.int64, sizeof(bh_int64)); // <sweep-dim>
    }
    os.write((char*)&inst_sep, sizeof(inst_sep));                       // <inst_sep>
}

static void hashOpid(std::ostream& os, const bh_instruction& instr, BatchHash& batchHash)
{
    /* The Instruction hash consists of the following fields:
     * (<operant-id>)[1]  <seperator>
     * 1: for each operand
     */
    int noperands = bh_operands(instr.opcode);
    for(int oidx=0; oidx<noperands; ++oidx) {
        const bh_view& view = instr.operand[oidx];
        if (bh_is_constant(&view))
            continue;  // Ignore constants
        std::pair<size_t,bool> vid = batchHash.views.insert(view);
        size_t id = vid.first;
        os.write((char*)&id, sizeof(id));                               // <operant-id>
    }
    os.write((char*)&inst_sep, sizeof(inst_sep));                       // <inst_sep>
}

#define __scalar(i) (bh_is_scalar(&(i)->operand[0]) || \
                     (bh_opcode_is_accumulate((i)->opcode) && (i)->operand[0].ndim == 1))

typedef void (*InstrHash)(std::ostream& os, const bh_instruction &instr, BatchHash& batchHash);

static InstrHash getInstrHash(FuseModel fuseModel)
{
    switch(fuseModel)
    {
    case BROADEST:
        return &hashOpid;
    case NO_XSWEEP:
        return &hashOpidSweepdim;
    case NO_XSWEEP_SCALAR_SEPERATE:
        return &hashScalarOpidSweepdim;
    case NO_XSWEEP_SCALAR_SEPERATE_SHAPE_MATCH:
        return &hashScalarShapeidOpidSweepdim;
    case SAME_SHAPE:
    case SAME_SHAPE_RANGE:
    case SAME_SHAPE_RANDOM:
    case SAME_SHAPE_RANGE_RANDOM:
    case SAME_SHAPE_GENERATE_1DREDUCE:
        return &hashOpcodeOpidShapeidSweepdim;
    default:
        throw runtime_error("Could not find valid hash function for fuse model.");
    }
}

//Constructor of the BatchHash class
BatchHash::BatchHash(const vector<bh_instruction> &instr_list)
{
    InstrHash hashFn = getInstrHash(fuse_get_selected_model());
    std::ostringstream data(std::ios_base::ate);
    for(const bh_instruction& instr: instr_list)
    {
        hashFn(data, instr, *this);
    }
    boost::hash<string> hasher;
    _hash = hasher(data.str());
}

InstrIndexesList &FuseCache::insert(const BatchHash &batch,
                                    const vector<bh_ir_kernel> &kernel_list)
{
    cache[batch.hash()] = InstrIndexesList(kernel_list, batch.hash(), fuser_name);
    return cache[batch.hash()];
}

bool FuseCache::lookup(const BatchHash &batch,
                       bh_ir &bhir,
                       vector<bh_ir_kernel> &kernel_list) const
{
    assert(kernel_list.size() == 0);
    CacheMap::const_iterator it = cache.find(batch.hash());
    if(deactivated or it == cache.end())
    {
        return false;
    }
    else
    {
        it->second.fill_kernel_list(bhir, kernel_list);
        return true;
    }
}

void FuseCache::write_to_files() const
{
    if(deactivated)
        return;
    if(dir_path == NULL)
    {
        cout << "[FUSE-CACHE] Couldn't find the 'cache_path' key in "   \
            "the configure file thus no cache files are written to disk!" << endl;
        return;
    }
    path cache_dir(dir_path);
    if(create_directories(cache_dir))
    {
        cout << "[FUSE-CACHE] Creating cache diretory " << cache_dir << endl;
#if BOOST_VERSION > 104900
            permissions(cache_dir, all_all);
#endif
    }

    path tmp_dir = cache_dir / unique_path();
    create_directories(tmp_dir);
    for(CacheMap::const_iterator it=cache.begin(); it != cache.end(); ++it)
    {
        string name;
        it->second.get_filename(name);
        path shared_name = cache_dir / name;

        if(exists(shared_name))
            continue;//No need to overwrite an existing file

        path unique_name = tmp_dir / name;
        ofstream ofs(unique_name.string().c_str());
        boost::archive::text_oarchive oa(ofs);
        oa << it->second;
        ofs.close();
#if BOOST_VERSION > 104900
        permissions(unique_name, all_all);
#endif
        rename(unique_name, shared_name);
    }
    remove(tmp_dir);
}

void FuseCache::load_from_files()
{
    if(dir_path == NULL)
    {
        cout << "[FUSE-CACHE] Couldn't find the 'cache_path' key in "   \
            "the configure file thus no cache files are loaded from disk!" << endl;
        return;
    }
    path p(dir_path);
    if(not (exists(p) and is_directory(p)))
        return;

    string fuse_model_name;
    fuse_model_text(fuse_get_selected_model(), fuse_model_name);

    //Iterate the 'dir_path' diretory and load each file
    directory_iterator it(p), eod;
    BOOST_FOREACH(const path &f, make_pair(it, eod))
    {
        if(is_regular_file(f))
        {
            int tries = 0;
            while(1)
            {
                try
                {
                    ifstream ifs(f.string().c_str());
                    boost::archive::text_iarchive ia(ifs);
                    InstrIndexesList t;
                    ia >> t;
                    if(iequals(t.fuser_name(), fuser_name) and
                       iequals(t.fuse_model(), fuse_model_name))
                    {
                        cache[t.hash()] = t;
                    }
                }
                catch(const std::exception &e)
                {
                    if(++tries >= 10)
                    {
                        cerr << "[FUSE-CACHE] failed to open file '" << f.string();
                        cerr << "' (" << tries << " tries): " << e.what() << endl;
                    }
                    else
                        continue;
                }
                break;
            }
        }
    }
}
} //namespace bohrium
<commit_msg>fuse-cache: fixed BUG where hashScalarShapeidOpidSweepdim() didn't ignore BH_NONE operations<commit_after>/*
This file is part of Bohrium and copyright (c) 2012 the Bohrium
team <http://www.bh107.org>.

Bohrium is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3
of the License, or (at your option) any later version.

Bohrium is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with Bohrium.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <string>
#include <cstring>
#include <bh.h>
#include "bh_fuse.h"
#include "bh_fuse_cache.h"
#include <fstream>
#include <exception>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/version.hpp>
#include <boost/algorithm/string/predicate.hpp> //For iequals()

using namespace std;
using namespace boost;
using namespace boost::filesystem;

namespace bohrium {

/* * OBS * OBS * OBS * OBS * OBS * OBS * OBS * OBS * OBS * OBS * OBS * OBS
 * When designing an instruction hash function REMEMBER:
 * The hash string should either be of fixed length and all feilds
 * contained also be of fixed legth OR unique seperators should be
 * used for each variable length field and to seperate instruction
 * hashed. The function hashOpcodeIdShapeSweepdim may be used as
 * inspiration.
 */

static const size_t inst_sep = SIZE_MAX;
static const size_t op_sep   = SIZE_MAX-1;

static void hashOpcodeOpidShapeidSweepdim(std::ostream& os, const bh_instruction& instr,
                                        BatchHash& batchHash)
{
    /* The Instruction hash consists of the following fields:
     * <opcode> (<operant-id> <ndim> <shape> <op_sep>)[1] <sweep-dim>[2] <inst_sep>
     * 1: for each operand
     * 2: if the operation is a sweep operation
     */
    int noperands = bh_operands(instr.opcode);
    os.write((const char*)&instr.opcode, sizeof(instr.opcode));         // <opcode>
    for(int oidx=0; oidx<noperands; ++oidx) {
        const bh_view& view = instr.operand[oidx];
        if (bh_is_constant(&view))
            continue;  // Ignore constants
        std::pair<size_t,bool> vid = batchHash.views.insert(view);
        size_t id = vid.first;
        os.write((char*)&id, sizeof(id));                               // <operant-id>
        os.write((char*)&view.ndim, sizeof(view.ndim));                 // <ndim>
        std::pair<size_t,bool> sidp = batchHash.shapes.insert(std::vector<bh_index>(view.shape,view.shape+view.ndim));
        os.write((char*)&sidp.first, sizeof(sidp.first));                   // <shape-id>
        os.write((char*)&op_sep, sizeof(op_sep));                       // <op_sep>
    }
    if (bh_opcode_is_sweep(instr.opcode))
        os.write((char*)&instr.constant.value.int64, sizeof(bh_int64)); // <sweep-dim>
    os.write((char*)&inst_sep, sizeof(inst_sep));                       // <inst_sep>
}

static void hashOpidSweepdim(std::ostream& os, const bh_instruction& instr, BatchHash& batchHash)
{
    /* The Instruction hash consists of the following fields:
     * (<operant-id>)[1] <op_sep> (<ndim> <sweep-dim>)[2] <seperator>
     * 1: for each operand
     * 2: if the operation is a sweep operation
     */
    int noperands = bh_operands(instr.opcode);
    for(int oidx=0; oidx<noperands; ++oidx) {
        const bh_view& view = instr.operand[oidx];
        if (bh_is_constant(&view))
            continue;  // Ignore constants
        std::pair<size_t,bool> vid = batchHash.views.insert(view);
        size_t id = vid.first;
        os.write((char*)&id, sizeof(id));                               // <operant-id>
    }
    os.write((char*)&op_sep, sizeof(op_sep));                           // <op_sep>
    if (bh_opcode_is_sweep(instr.opcode))
    {
        const bh_view& view = instr.operand[1];
        os.write((char*)&view.ndim, sizeof(view.ndim));                 // <ndim>
        os.write((char*)&instr.constant.value.int64, sizeof(bh_int64)); // <sweep-dim>
    }
    os.write((char*)&inst_sep, sizeof(inst_sep));                       // <inst_sep>
}

static void hashScalarOpidSweepdim(std::ostream& os, const bh_instruction& instr, BatchHash& batchHash)
{
    /* The Instruction hash consists of the following fields:
     * <is_scalar> (<operant-id>)[1] <op_sep> (<ndim> <sweep-dim>)[2] <seperator>
     * 1: for each operand
     * 2: if the operation is a sweep operation
     */
    bool scalar = (bh_is_scalar(&(instr.operand[0])) ||
                   (bh_opcode_is_accumulate(instr.opcode) && instr.operand[0].ndim == 1));
    os.write((char*)&scalar, sizeof(scalar));                           // <is_scalar>
    int noperands = bh_operands(instr.opcode);
    for(int oidx=0; oidx<noperands; ++oidx) {
        const bh_view& view = instr.operand[oidx];
        if (bh_is_constant(&view))
            continue;  // Ignore constants
        std::pair<size_t,bool> vid = batchHash.views.insert(view);
        size_t id = vid.first;
        os.write((char*)&id, sizeof(id));                               // <operant-id>
    }
    os.write((char*)&op_sep, sizeof(op_sep));                           // <op_sep>
    if (bh_opcode_is_sweep(instr.opcode))
    {
        const bh_view& view = instr.operand[1];
        os.write((char*)&view.ndim, sizeof(view.ndim));                 // <ndim>
        os.write((char*)&instr.constant.value.int64, sizeof(bh_int64)); // <sweep-dim>
    }
    os.write((char*)&inst_sep, sizeof(inst_sep));                       // <inst_sep>
}

static void hashScalarShapeidOpidSweepdim(std::ostream& os, const bh_instruction& instr, BatchHash& batchHash)
{
    /* The Instruction hash consists of the following fields:
     * <is_scalar> <shape-id> (<operant-id>)[1] <op_sep> (<ndim> <sweep-dim>)[2] <seperator>
     * 1: for each operand
     * 2: if the operation is a sweep operation
     * NB: but ignores instructions that takes no arguments, such as BH_NONE
     */
    int noperands = bh_operands(instr.opcode);
    if(noperands == 0)
        return;
    bool scalar = (bh_is_scalar(&(instr.operand[0])) ||
                   (bh_opcode_is_accumulate(instr.opcode) && instr.operand[0].ndim == 1));
    os.write((char*)&scalar, sizeof(scalar));                           // <is_scalar>
    const bh_view& view = (bh_opcode_is_sweep(instr.opcode) ? instr.operand[1] : instr.operand[0]);
    std::pair<size_t,bool> sidp = batchHash.shapes.insert(std::vector<bh_index>(view.shape,view.shape+view.ndim));
    os.write((char*)&sidp.first, sizeof(sidp.first));                   // <shape-id>
    for(int oidx=0; oidx<noperands; ++oidx) {
        const bh_view& view = instr.operand[oidx];
        if (bh_is_constant(&view))
            continue;  // Ignore constants
        std::pair<size_t,bool> vid = batchHash.views.insert(view);
        size_t id = vid.first;
        os.write((char*)&id, sizeof(id));                               // <operant-id>
    }
    os.write((char*)&op_sep, sizeof(op_sep));                           // <op_sep>
    if (bh_opcode_is_sweep(instr.opcode))
    {
        const bh_view& view = instr.operand[1];
        os.write((char*)&view.ndim, sizeof(view.ndim));                 // <ndim>
        os.write((char*)&instr.constant.value.int64, sizeof(bh_int64)); // <sweep-dim>
    }
    os.write((char*)&inst_sep, sizeof(inst_sep));                       // <inst_sep>
}

static void hashOpid(std::ostream& os, const bh_instruction& instr, BatchHash& batchHash)
{
    /* The Instruction hash consists of the following fields:
     * (<operant-id>)[1]  <seperator>
     * 1: for each operand
     */
    int noperands = bh_operands(instr.opcode);
    for(int oidx=0; oidx<noperands; ++oidx) {
        const bh_view& view = instr.operand[oidx];
        if (bh_is_constant(&view))
            continue;  // Ignore constants
        std::pair<size_t,bool> vid = batchHash.views.insert(view);
        size_t id = vid.first;
        os.write((char*)&id, sizeof(id));                               // <operant-id>
    }
    os.write((char*)&inst_sep, sizeof(inst_sep));                       // <inst_sep>
}

#define __scalar(i) (bh_is_scalar(&(i)->operand[0]) || \
                     (bh_opcode_is_accumulate((i)->opcode) && (i)->operand[0].ndim == 1))

typedef void (*InstrHash)(std::ostream& os, const bh_instruction &instr, BatchHash& batchHash);

static InstrHash getInstrHash(FuseModel fuseModel)
{
    switch(fuseModel)
    {
    case BROADEST:
        return &hashOpid;
    case NO_XSWEEP:
        return &hashOpidSweepdim;
    case NO_XSWEEP_SCALAR_SEPERATE:
        return &hashScalarOpidSweepdim;
    case NO_XSWEEP_SCALAR_SEPERATE_SHAPE_MATCH:
        return &hashScalarShapeidOpidSweepdim;
    case SAME_SHAPE:
    case SAME_SHAPE_RANGE:
    case SAME_SHAPE_RANDOM:
    case SAME_SHAPE_RANGE_RANDOM:
    case SAME_SHAPE_GENERATE_1DREDUCE:
        return &hashOpcodeOpidShapeidSweepdim;
    default:
        throw runtime_error("Could not find valid hash function for fuse model.");
    }
}

//Constructor of the BatchHash class
BatchHash::BatchHash(const vector<bh_instruction> &instr_list)
{
    InstrHash hashFn = getInstrHash(fuse_get_selected_model());
    std::ostringstream data(std::ios_base::ate);
    for(const bh_instruction& instr: instr_list)
    {
        hashFn(data, instr, *this);
    }
    boost::hash<string> hasher;
    _hash = hasher(data.str());
}

InstrIndexesList &FuseCache::insert(const BatchHash &batch,
                                    const vector<bh_ir_kernel> &kernel_list)
{
    cache[batch.hash()] = InstrIndexesList(kernel_list, batch.hash(), fuser_name);
    return cache[batch.hash()];
}

bool FuseCache::lookup(const BatchHash &batch,
                       bh_ir &bhir,
                       vector<bh_ir_kernel> &kernel_list) const
{
    assert(kernel_list.size() == 0);
    CacheMap::const_iterator it = cache.find(batch.hash());
    if(deactivated or it == cache.end())
    {
        return false;
    }
    else
    {
        it->second.fill_kernel_list(bhir, kernel_list);
        return true;
    }
}

void FuseCache::write_to_files() const
{
    if(deactivated)
        return;
    if(dir_path == NULL)
    {
        cout << "[FUSE-CACHE] Couldn't find the 'cache_path' key in "   \
            "the configure file thus no cache files are written to disk!" << endl;
        return;
    }
    path cache_dir(dir_path);
    if(create_directories(cache_dir))
    {
        cout << "[FUSE-CACHE] Creating cache diretory " << cache_dir << endl;
#if BOOST_VERSION > 104900
            permissions(cache_dir, all_all);
#endif
    }

    path tmp_dir = cache_dir / unique_path();
    create_directories(tmp_dir);
    for(CacheMap::const_iterator it=cache.begin(); it != cache.end(); ++it)
    {
        string name;
        it->second.get_filename(name);
        path shared_name = cache_dir / name;

        if(exists(shared_name))
            continue;//No need to overwrite an existing file

        path unique_name = tmp_dir / name;
        ofstream ofs(unique_name.string().c_str());
        boost::archive::text_oarchive oa(ofs);
        oa << it->second;
        ofs.close();
#if BOOST_VERSION > 104900
        permissions(unique_name, all_all);
#endif
        rename(unique_name, shared_name);
    }
    remove(tmp_dir);
}

void FuseCache::load_from_files()
{
    if(dir_path == NULL)
    {
        cout << "[FUSE-CACHE] Couldn't find the 'cache_path' key in "   \
            "the configure file thus no cache files are loaded from disk!" << endl;
        return;
    }
    path p(dir_path);
    if(not (exists(p) and is_directory(p)))
        return;

    string fuse_model_name;
    fuse_model_text(fuse_get_selected_model(), fuse_model_name);

    //Iterate the 'dir_path' diretory and load each file
    directory_iterator it(p), eod;
    BOOST_FOREACH(const path &f, make_pair(it, eod))
    {
        if(is_regular_file(f))
        {
            int tries = 0;
            while(1)
            {
                try
                {
                    ifstream ifs(f.string().c_str());
                    boost::archive::text_iarchive ia(ifs);
                    InstrIndexesList t;
                    ia >> t;
                    if(iequals(t.fuser_name(), fuser_name) and
                       iequals(t.fuse_model(), fuse_model_name))
                    {
                        cache[t.hash()] = t;
                    }
                }
                catch(const std::exception &e)
                {
                    if(++tries >= 10)
                    {
                        cerr << "[FUSE-CACHE] failed to open file '" << f.string();
                        cerr << "' (" << tries << " tries): " << e.what() << endl;
                    }
                    else
                        continue;
                }
                break;
            }
        }
    }
}
} //namespace bohrium
<|endoftext|>