<commit_before>#define BOOST_TEST_MODULE OctreeTest

#include <boost/test/unit_test.hpp>

#include <string>

#include "octree.h"
#include "tensor.h"

using namespace nbody;

struct Leaf;
struct Node;

using TestOctree = Octree<Leaf, Node, 3>;
using TestQuadtree = Octree<Leaf, Node, 2>;

struct Leaf {
	std::size_t data;
	explicit Leaf(int data) : data(data) {
	}
};

struct Node {
	std::size_t data;
	explicit Node(int data = 0) : data(data) {
	}
};

// Insert 8 leafs into an octree, one per octant.
BOOST_AUTO_TEST_CASE(OctreeShallowInsertTest) {
	TestOctree octree(
		{0.0, 0.0, 0.0},
		{1.0, 1.0, 1.0},
		3, 4);

	// Put a single leaf in each octant of the octree. Check that after the
	// third insertion, the root node subdivides.
	for (std::size_t index = 0; index < 8; ++index) {
		Vector<3> position = {
			(Scalar) (index >> 0 & 1),
			(Scalar) (index >> 1 & 1),
			(Scalar) (index >> 2 & 1)
		};
		position *= 0.9;
		position += {0.05, 0.05, 0.05};
		octree.insert(Leaf(index), position);
		if (index < 3) {
			BOOST_REQUIRE_MESSAGE(
				octree.nodes().size() == 1,
				"the root node should have no children for " +
				std::to_string(index + 1) + " leafs");
		}
		else {
			BOOST_REQUIRE_MESSAGE(
				octree.nodes().size() == 9,
				"the root node should have children for " +
				std::to_string(index + 1) + " leafs");
		}
	}

	BOOST_REQUIRE_MESSAGE(
		octree.leafs().size() == 8,
		"root should have 8 leafs");

	TestOctree::NodeIterator root = octree.nodes().begin();

	BOOST_REQUIRE_MESSAGE(
		root.hasChildren(),
		"root should have child nodes");

	TestOctree::NodeRange children = root.children();

	BOOST_REQUIRE_MESSAGE(
		children.size() == 8,
		"root should have 8 children");

	for (std::size_t index = 0; index < 8; ++index) {
		TestOctree::NodeIterator child = children.begin() + index;
		TestOctree::LeafRange leafs = child.leafs();
		TestOctree::LeafIterator leaf = leafs.begin();
		BOOST_REQUIRE_MESSAGE(
			leafs.size() == 1,
			"child " << index << " should have 1 leaf");
		BOOST_REQUIRE_MESSAGE(
			leaf->data == index,
			"leaf has data " << leaf->data << ", should be " << index);
	}
}

// Insert a number of leafs into a quadtree, testing deeper insertion.
BOOST_AUTO_TEST_CASE(OctreeDeepInsertTest) {
	TestQuadtree quadtree(
		{0.0, 0.0},
		{16.0, 16.0},
		3, 4);

	// The positions where the leafs will be placed.
	Vector<2> positions[] = {
		{1,  2},
		{6,  2},
		{6,  6},
		{3,  2},
		{2,  6},
		{14, 6},
		{6,  14},
		{6,  10},
		{2,  10},
		{2,  14},

		{10, 6},
		{10, 2},
		{9,  9},
		{15, 1},
		{13, 3},
		{15, 3},
		{13, 1},
		{11, 9},
		{9,  11},
		{11, 11},

		{15, 9},
		{15, 13},
		{15, 11},
		{15, 15},
		{13, 9},
		{13, 13},
		{11, 13},
		{9,  13},
		{11, 15},
		{9,  15},
	};
	std::size_t numLeafs = sizeof(positions) / sizeof(positions[0]);

	// These arrays are used to verify that the structure of the quadtree is
	// correct.

	// The iteration order over the leafs (with depth-first).
	std::size_t order[] = {
		0,  3,  1,  4,  2,  11, 16, 13, 14, 15,
		10, 5,  8,  7,  9,  6,  12, 17, 18, 19,
		20, 22, 24, 27, 26, 29, 28, 21, 23, 25,
	};
	// Which nodes in the depth-first iteration order have children.
	bool nodeHasChildren[] = {
		true,
			true, false, false, false, false,
			true,
				false,
				true, false, false, false, false,
				false,
				false,
			true, false, false, false, false,
			true,
				true, false, false, false, false,
				false,
				true, false, false, false, false,
				false,
	};
	// How many leafs each node should have.
	std::size_t nodeNumLeafs[] = {
		30,
			5, 2, 1, 1, 1,
			7, 1, 4, 1, 1, 1, 1, 1, 1,
			4, 1, 1, 1, 1,
			14, 4, 1, 1, 1, 1, 3, 4, 1, 1, 1, 1, 3,
	};

	for (std::size_t index = 0; index < numLeafs; ++index) {
		quadtree.insert(Leaf(index), positions[index]);
	}

	// Iterate over both the leafs and the nodes and compare them to the arrays
	// from above.
	for (std::size_t index = 0; index < numLeafs; ++index) {
		std::size_t leafData = quadtree.leafs()[index].data;
		BOOST_REQUIRE_MESSAGE(
			leafData == order[index],
			"leaf at index " + std::to_string(index) +
			" should have data " + std::to_string(order[index]) +
			" instead of data " + std::to_string(leafData));
	}

	std::size_t nodeIndex = 0;
	TestQuadtree::NodeIterator nodeIt = quadtree.nodes().begin();
	while (nodeIt != quadtree.nodes().end()) {
		BOOST_REQUIRE_MESSAGE(
			nodeIt.hasChildren() == nodeHasChildren[nodeIndex],
			"node at index " + std::to_string(nodeIndex) + " should" +
			(!nodeHasChildren[nodeIndex] ? " not" : "") + " have children");
		BOOST_REQUIRE_MESSAGE(
			nodeIt.leafs().size() == nodeNumLeafs[nodeIndex],
			"node at index " + std::to_string(nodeIndex) +
			" should have " + std::to_string(nodeNumLeafs[nodeIndex]) +
			" leafs instead of " + std::to_string(nodeIt.leafs().size()) +
			" leafs");
		++nodeIndex;
		++nodeIt;
	}
}

BOOST_AUTO_TEST_CASE(OctreeSamePointInsertTest) {
	// Create a quadtree with a maximum depth of 3. This corresponds to 4
	// generations of nodes (since the root node is at a depth of 0).
	TestQuadtree quadtree(
		{0.0, 0.0},
		{1.0, 1.0},
		3, 3);

	for (std::size_t index = 0; index < 4; ++index) {
		quadtree.insert(Leaf(index), {1.0 / 16.0, 1.0 / 16.0});
	}

	TestQuadtree::NodeIterator bottomNodeIt = quadtree.nodes().begin() + 3;
	BOOST_REQUIRE_MESSAGE(
		!bottomNodeIt.hasChildren(),
		"deepest node shouldn't have children");
	BOOST_REQUIRE_MESSAGE(
		bottomNodeIt.leafs().size() == 4,
		"deepest node should have 4 children");

	for (std::size_t index = 0; index < quadtree.leafs().size(); ++index) {
		std::size_t data = bottomNodeIt.leafs()[index].data;
		BOOST_REQUIRE_MESSAGE(
			data == index,
			"node at index " + std::to_string(index) +
			" has data " + std::to_string(data));
	}
}

BOOST_AUTO_TEST_CASE(OctreeShallowEraseTest) {
	TestOctree octree(
		{0.0, 0.0, 0.0},
		{1.0, 1.0, 1.0},
		3, 4);

	// Insert a single point into each quadrant.
	for (std::size_t index = 0; index < 8; ++index) {
		Vector<3> position = {
			(Scalar) (index >> 0 & 1),
			(Scalar) (index >> 1 & 1),
			(Scalar) (index >> 2 & 1)
		};
		position *= 0.9;
		position += {0.05, 0.05, 0.05};
		octree.insert(Leaf(index), position);
	}

	// Remove the points one at a time. Check that the number of nodes decreases
	// correctly as points are removed.
	for (std::size_t index = 8; index-- > 0; ) {
		TestOctree::LeafIterator leaf = octree.leafs().end() - 1;
		BOOST_REQUIRE_MESSAGE(
			leaf->data == index,
			"leaf at index " + std::to_string(index) +
			" has data " + std::to_string(leaf->data));
		octree.erase(leaf);
		if (index <= 3) {
			BOOST_REQUIRE_MESSAGE(
				octree.nodes().size() == 1,
				"the root node should have no children for " +
				std::to_string(index) + " leafs");
		}
		else {
			BOOST_REQUIRE_MESSAGE(
				octree.nodes().size() == 9,
				"the root node should have children for " +
				std::to_string(index) + " leafs");
		}
	}
}

<commit_msg>Added a method for verifying the structure of an octree<commit_after>#define BOOST_TEST_MODULE OctreeTest

#include <boost/test/unit_test.hpp>

#include <algorithm>
#include <iterator>
#include <string>
#include <utility>
#include <vector>

#include "octree.h"
#include "tensor.h"

using namespace nbody;

struct Leaf;
struct Node;

using TestOctree = Octree<Leaf, Node, 3>;
using TestQuadtree = Octree<Leaf, Node, 2>;

struct Leaf {
	std::size_t data;
	explicit Leaf(int data) : data(data) {
	}
	bool operator==(Leaf const& other) const {
		return data == other.data;
	}
	bool operator!=(Leaf const& other) const {
		return data != other.data;
	}
};

struct Node {
	std::size_t data;
	explicit Node(int data = 0) : data(data) {
	}
	bool operator==(Node const& other) const {
		return data == other.data;
	}
	bool operator!=(Node const& other) const {
		return data != other.data;
	}
};

enum class CheckOctreeResult {
	Success,
	RootHasParent,
	LeafDuplicate,
	LeafMissing,
	DepthIncorrect,
	LeafOutOfBounds,
	NodeOverCapacity,
	NodeOverDepth,
	NodeUnderCapacity,
	ChildLeafDuplicate,
	ChildLeafMissing,
	ChildParentMismatch,
	LeafNotInChild,
	LeafNotInParent,
	ChildCountMismatch,
};

// Takes an octree and a list of leafs that should be contained within the
// octree. Returns whether the structure of the octree is correct for the given
// points.
template<std::size_t Dim>
CheckOctreeResult checkOctree(
		Octree<Leaf, Node, Dim> const& octree,
		std::vector<std::pair<Leaf, Vector<Dim> > > allLeafPairs) {
	// Create a stack storing the points that belong to the current node.
	std::vector<std::vector<std::pair<Leaf, Vector<Dim> > > > stack;
	stack.push_back(allLeafPairs);

	// Check that the root node has no parent.
	if (octree.nodes().begin().hasParent()) {
		return CheckOctreeResult::RootHasParent;
	}

	// Loop through all of the nodes.
	for (
			auto node = octree.nodes().begin();
			node != octree.nodes().end();
			++node) {
		// Check that the current node has depth of +1 from its parent.
		if (node.depth() !=
				(node.hasParent() ? node.parent().depth() + 1 : 0)) {
			return CheckOctreeResult::DepthIncorrect;
		}

		// Take the top of the stack, and check whether each of the
		// leaf-position pairs are within the dimensions.
		std::vector<std::pair<Leaf, Vector<Dim> > > leafPairs(stack.back());
		stack.pop_back();

		if (leafPairs.size() > node.leafs().size()) {
			return CheckOctreeResult::LeafDuplicate;
		}
		if (leafPairs.size() < node.leafs().size()) {
			return CheckOctreeResult::LeafMissing;
		}

		for (auto leafPair : leafPairs) {
			auto leaf = std::find(
				node.leafs().begin(),
				node.leafs().end(),
				leafPair.first);
			if (leaf == node.leafs().end()) {
				return CheckOctreeResult::LeafMissing;
			}
			if (leaf.position() != leafPair.second) {
				for (std::size_t dim = 0; dim < Dim; ++dim) {
					Scalar lower = node.position()[dim];
					Scalar upper = lower + node.dimensions()[dim];
					if (!(
							leaf.position()[dim] >= lower &&
							leaf.position()[dim] < upper)) {
						return CheckOctreeResult::LeafOutOfBounds;
					}
				}
			}
		}

		if (!node.hasChildren()) {
			// If the node doesn't have children, then make sure that it doesn't
			// have too many leafs and that it isn't too deep.
			if (node.leafs().size() > octree.nodeCapacity()) {
				return CheckOctreeResult::NodeOverCapacity;
			}
			if (node.depth() > octree.maxDepth()) {
				return CheckOctreeResult::NodeOverDepth;
			}
		}
		else {
			// Otherwise, make sure it doens't have too few leafs either.
			if (node.leafs().size() <= octree.nodeCapacity()) {
				return CheckOctreeResult::NodeUnderCapacity;
			}
			for (
					std::size_t childIndex = 0;
					childIndex < (1 << Dim);
					++childIndex) {
				auto child = node.child(childIndex);

				// Check that the child's parent is this node.
				if (child.parent() != node) {
					return CheckOctreeResult::ChildParentMismatch;
				}
				// Create a vector to store the leaf-position pairs that belong
				// to the child.
				std::vector<std::pair<Leaf, Vector<Dim> > > childLeafPairs;
				auto lastChildLeaf = std::partition(
					leafPairs.begin(),
					leafPairs.end(),
					[child](std::pair<Leaf, Vector<Dim> > leafPair) {
						auto begin = child.leafs().begin();
						auto end = child.leafs().end();
						return std::find(begin, end, leafPair.first) != end;
					});
				std::copy(
					leafPairs.begin(),
					lastChildLeaf,
					std::back_inserter(childLeafPairs));
				leafPairs.erase(leafPairs.begin(), lastChildLeaf);

				// Put the child leaf pairs onto the stack.
				if (childLeafPairs.size() != child.leafs().size()) {
					return CheckOctreeResult::LeafNotInParent;
				}
				stack.push_back(childLeafPairs);
			}
			// Check that each of the leaf-position pairs belonged to at least
			// one of the children.
			if (!leafPairs.empty()) {
				return CheckOctreeResult::LeafNotInChild;
			}
		}
	}

	// The stack should be empty, except if one of the nodes didn't have the
	// right number of children.
	if (!stack.empty()) {
		return CheckOctreeResult::ChildCountMismatch;
	}

	return CheckOctreeResult::Success;
}

// Insert 8 leafs into an octree, one per octant.
BOOST_AUTO_TEST_CASE(OctreeShallowInsertTest) {
	TestOctree octree(
		{0.0, 0.0, 0.0},
		{1.0, 1.0, 1.0},
		3, 4);

	// Put a single leaf in each octant of the octree. Check that after the
	// third insertion, the root node subdivides.
	for (std::size_t index = 0; index < 8; ++index) {
		Vector<3> position = {
			(Scalar) (index >> 0 & 1),
			(Scalar) (index >> 1 & 1),
			(Scalar) (index >> 2 & 1)
		};
		position *= 0.9;
		position += {0.05, 0.05, 0.05};
		octree.insert(Leaf(index), position);
		if (index < 3) {
			BOOST_REQUIRE_MESSAGE(
				octree.nodes().size() == 1,
				"the root node should have no children for " +
				std::to_string(index + 1) + " leafs");
		}
		else {
			BOOST_REQUIRE_MESSAGE(
				octree.nodes().size() == 9,
				"the root node should have children for " +
				std::to_string(index + 1) + " leafs");
		}
	}

	BOOST_REQUIRE_MESSAGE(
		octree.leafs().size() == 8,
		"root should have 8 leafs");

	TestOctree::NodeIterator root = octree.nodes().begin();

	BOOST_REQUIRE_MESSAGE(
		root.hasChildren(),
		"root should have child nodes");

	TestOctree::NodeRange children = root.children();

	BOOST_REQUIRE_MESSAGE(
		children.size() == 8,
		"root should have 8 children");

	for (std::size_t index = 0; index < 8; ++index) {
		TestOctree::NodeIterator child = children.begin() + index;
		TestOctree::LeafRange leafs = child.leafs();
		TestOctree::LeafIterator leaf = leafs.begin();
		BOOST_REQUIRE_MESSAGE(
			leafs.size() == 1,
			"child " << index << " should have 1 leaf");
		BOOST_REQUIRE_MESSAGE(
			leaf->data == index,
			"leaf has data " << leaf->data << ", should be " << index);
	}
}

BOOST_AUTO_TEST_CASE(OctreeCheckTest) {
	TestQuadtree quadtree(
		{0.0, 0.0},
		{16.0, 16.0},
		3, 4);
	Vector<2> positions[] = {
		{1,  2},
		{6,  2},
		{6,  6},
		{3,  2},
		{2,  6},
		{14, 6},
		{6,  14},
		{6,  10},
		{2,  10},
		{2,  14},

		{10, 6},
		{10, 2},
		{9,  9},
		{15, 1},
		{13, 3},
		{15, 3},
		{13, 1},
		{11, 9},
		{9,  11},
		{11, 11},

		{15, 9},
		{15, 13},
		{15, 11},
		{15, 15},
		{13, 9},
		{13, 13},
		{11, 13},
		{9,  13},
		{11, 15},
		{9,  15},
	};
	std::size_t numLeafs = sizeof(positions) / sizeof(positions[0]);
	std::vector<std::pair<Leaf, Vector<2> > > leafPairs;
	for (std::size_t index = 0; index < numLeafs; ++index) {
		Leaf leaf(index);
		Vector<2> position(positions[index]);
		leafPairs.push_back(std::make_pair(leaf, position));
		quadtree.insert(leaf, position);
	}
	CheckOctreeResult result = checkOctree(quadtree, leafPairs);
	BOOST_REQUIRE_MESSAGE(
		result == CheckOctreeResult::Success,
		"octree has invalid form (" + std::to_string((int) result) + ")");
}

// Insert a number of leafs into a quadtree, testing deeper insertion.
BOOST_AUTO_TEST_CASE(OctreeDeepInsertTest) {
	TestQuadtree quadtree(
		{0.0, 0.0},
		{16.0, 16.0},
		3, 4);

	// The positions where the leafs will be placed.
	Vector<2> positions[] = {
		{1,  2},
		{6,  2},
		{6,  6},
		{3,  2},
		{2,  6},
		{14, 6},
		{6,  14},
		{6,  10},
		{2,  10},
		{2,  14},

		{10, 6},
		{10, 2},
		{9,  9},
		{15, 1},
		{13, 3},
		{15, 3},
		{13, 1},
		{11, 9},
		{9,  11},
		{11, 11},

		{15, 9},
		{15, 13},
		{15, 11},
		{15, 15},
		{13, 9},
		{13, 13},
		{11, 13},
		{9,  13},
		{11, 15},
		{9,  15},
	};
	std::size_t numLeafs = sizeof(positions) / sizeof(positions[0]);

	// These arrays are used to verify that the structure of the quadtree is
	// correct.

	// The iteration order over the leafs (with depth-first).
	std::size_t order[] = {
		0,  3,  1,  4,  2,  11, 16, 13, 14, 15,
		10, 5,  8,  7,  9,  6,  12, 17, 18, 19,
		20, 22, 24, 27, 26, 29, 28, 21, 23, 25,
	};
	// Which nodes in the depth-first iteration order have children.
	bool nodeHasChildren[] = {
		true,
			true, false, false, false, false,
			true,
				false,
				true, false, false, false, false,
				false,
				false,
			true, false, false, false, false,
			true,
				true, false, false, false, false,
				false,
				true, false, false, false, false,
				false,
	};
	// How many leafs each node should have.
	std::size_t nodeNumLeafs[] = {
		30,
			5, 2, 1, 1, 1,
			7, 1, 4, 1, 1, 1, 1, 1, 1,
			4, 1, 1, 1, 1,
			14, 4, 1, 1, 1, 1, 3, 4, 1, 1, 1, 1, 3,
	};

	// Actually insert all of the leafs.
	for (std::size_t index = 0; index < numLeafs; ++index) {
		quadtree.insert(Leaf(index), positions[index]);
	}

	// Iterate over both the leafs and the nodes and compare them to the arrays
	// from above.
	for (std::size_t index = 0; index < numLeafs; ++index) {
		std::size_t leafData = quadtree.leafs()[index].data;
		BOOST_REQUIRE_MESSAGE(
			leafData == order[index],
			"leaf at index " + std::to_string(index) +
			" should have data " + std::to_string(order[index]) +
			" instead of data " + std::to_string(leafData));
	}

	std::size_t nodeIndex = 0;
	TestQuadtree::NodeIterator nodeIt = quadtree.nodes().begin();
	while (nodeIt != quadtree.nodes().end()) {
		BOOST_REQUIRE_MESSAGE(
			nodeIt.hasChildren() == nodeHasChildren[nodeIndex],
			"node at index " + std::to_string(nodeIndex) + " should" +
			(!nodeHasChildren[nodeIndex] ? " not" : "") + " have children");
		BOOST_REQUIRE_MESSAGE(
			nodeIt.leafs().size() == nodeNumLeafs[nodeIndex],
			"node at index " + std::to_string(nodeIndex) +
			" should have " + std::to_string(nodeNumLeafs[nodeIndex]) +
			" leafs instead of " + std::to_string(nodeIt.leafs().size()) +
			" leafs");
		++nodeIndex;
		++nodeIt;
	}
}

BOOST_AUTO_TEST_CASE(OctreeSamePointInsertTest) {
	// Create a quadtree with a maximum depth of 3. This corresponds to 4
	// generations of nodes (since the root node is at a depth of 0).
	TestQuadtree quadtree(
		{0.0, 0.0},
		{1.0, 1.0},
		3, 3);

	for (std::size_t index = 0; index < 4; ++index) {
		quadtree.insert(Leaf(index), {1.0 / 16.0, 1.0 / 16.0});
	}

	TestQuadtree::NodeIterator bottomNodeIt = quadtree.nodes().begin() + 3;
	BOOST_REQUIRE_MESSAGE(
		!bottomNodeIt.hasChildren(),
		"deepest node shouldn't have children");
	BOOST_REQUIRE_MESSAGE(
		bottomNodeIt.leafs().size() == 4,
		"deepest node should have 4 children");

	for (std::size_t index = 0; index < quadtree.leafs().size(); ++index) {
		std::size_t data = bottomNodeIt.leafs()[index].data;
		BOOST_REQUIRE_MESSAGE(
			data == index,
			"node at index " + std::to_string(index) +
			" has data " + std::to_string(data));
	}
}

BOOST_AUTO_TEST_CASE(OctreeShallowEraseTest) {
	TestOctree octree(
		{0.0, 0.0, 0.0},
		{1.0, 1.0, 1.0},
		3, 4);

	// Insert a single point into each quadrant.
	for (std::size_t index = 0; index < 8; ++index) {
		Vector<3> position = {
			(Scalar) (index >> 0 & 1),
			(Scalar) (index >> 1 & 1),
			(Scalar) (index >> 2 & 1)
		};
		position *= 0.9;
		position += {0.05, 0.05, 0.05};
		octree.insert(Leaf(index), position);
	}

	// Remove the points one at a time. Check that the number of nodes decreases
	// correctly as points are removed.
	for (std::size_t index = 8; index-- > 0; ) {
		TestOctree::LeafIterator leaf = octree.leafs().end() - 1;
		BOOST_REQUIRE_MESSAGE(
			leaf->data == index,
			"leaf at index " + std::to_string(index) +
			" has data " + std::to_string(leaf->data));
		octree.erase(leaf);
		if (index <= 3) {
			BOOST_REQUIRE_MESSAGE(
				octree.nodes().size() == 1,
				"the root node should have no children for " +
				std::to_string(index) + " leafs");
		}
		else {
			BOOST_REQUIRE_MESSAGE(
				octree.nodes().size() == 9,
				"the root node should have children for " +
				std::to_string(index) + " leafs");
		}
	}
}

BOOST_AUTO_TEST_CASE(OctreeDeepEraseTest) {
	TestQuadtree quadtree(
		{0.0, 0.0},
		{16.0, 16.0},
		3, 4);

	// The positions where the leafs will be placed.
	Vector<2> positions[] = {
		{1,  2},
		{6,  2},
		{6,  6},
		{3,  2},
		{2,  6},
		{14, 6},
		{6,  14},
		{6,  10},
		{2,  10},
		{2,  14},

		{10, 6},
		{10, 2},
		{9,  9},
		{15, 1},
		{13, 3},
		{15, 3},
		{13, 1},
		{11, 9},
		{9,  11},
		{11, 11},

		{15, 9},
		{15, 13},
		{15, 11},
		{15, 15},
		{13, 9},
		{13, 13},
		{11, 13},
		{9,  13},
		{11, 15},
		{9,  15},
	};
	std::size_t numLeafs = sizeof(positions) / sizeof(positions[0]);

	// Insert all of the leafs.
	for (std::size_t index = 0; index < numLeafs; ++index) {
		quadtree.insert(Leaf(index), positions[index]);
	}
}

<|endoftext|>


<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: main.C,v 1.20.8.3 2007/03/26 07:11:33 amoll Exp $
//

// order of includes is important: first qapplication, than BALL includes
#include <QtGui/qapplication.h>
#include <BALL/CONFIG/config.h>

#ifdef BALL_HAS_GLEW
#	include <GL/glew.h>
#endif

#include <QtCore/QLocale>
#include <QtCore/QTranslator>

#include <QtGui/qmessagebox.h>
#include <QtGui/QSplashScreen>
#include <QtOpenGL/qgl.h>

#include "mainframe.h"
#include <BALL/SYSTEM/path.h>
#include <BALL/SYSTEM/directory.h>
#include <BALL/FORMAT/INIFile.h>
#include <BALL/SYSTEM/fileSystem.h>
#include <BALL/COMMON/logStream.h>

#include <iostream>

#ifdef Q_WS_X11
#include <X11/Xlib.h>
#endif

void logMessages(QtMsgType type, const char *msg)
{
	BALL::String s(msg);
	if (s.hasPrefix("QTextBrowser")) return;

	switch ( type ) {
		case QtDebugMsg:
				BALL::Log.info() << msg << std::endl;
				break;
		case QtWarningMsg:
				BALL::Log.warn() << msg << std::endl;
				break;
		case QtFatalMsg:
				fprintf( stderr, "Fatal: %s\n", msg );
				abort();                    // deliberately core dump
		case QtCriticalMsg:
				fprintf( stderr, "Critical: %s\n", msg );
				abort();                    // deliberately core dump
	}
}

// uncomment this to use debugging to std::cout!
//#undef BALL_OS_WINDOWS

#ifndef BALL_OS_WINDOWS
int main(int argc, char **argv)
{
#else
int WINAPI WinMain(HINSTANCE, HINSTANCE, PSTR cmd_line, int)
{
	int argc = __argc;
	char** argv = __argv;
#endif

#ifdef Q_WS_X11
    XInitThreads();
#endif

	qInstallMsgHandler(logMessages);

	putenv("BALL_RETURN_VALUE=");
	QApplication application(argc, argv);

  QPixmap splash_pm(":BALLView-1.3-Splashscreen.png");
  QSplashScreen* splash = new QSplashScreen(splash_pm);
  splash->show();

	// =============== testing for opengl support ======================================
	if (!QGLFormat::hasOpenGL())
	{
		QMessageBox::critical(0, "Error while starting BALLView",
				"Your computer has no OpenGL support, please install the correct drivers. Aborting for now...",
				QMessageBox::Ok, Qt::NoButton, Qt::NoButton);
		return -1;
	}

	BALL::String home_dir = BALL::Directory::getUserHomeDir();

	// =============== load translations =====================
	BALL::INIFile f(home_dir + BALL::FileSystem::PATH_SEPARATOR + ".BALLView");
	f.read();

	if(f.hasEntry("GENERAL", "language")) {
		QString str = f.getValue("GENERAL", "language").c_str();

		if(!(str == "Default")) {
			QString loc = "BALLView." + str;

			BALL::Path p;
			QStringList dpaths = QString(p.getDataPath().c_str()).split("\n");

			QTranslator* translator = new QTranslator(&application);
			foreach(QString str, dpaths) {
				translator->load(loc, str + "BALLView/translations");
				if(!translator->isEmpty()) {
					QCoreApplication::installTranslator(translator);
					break;
				}
			}
		}
	}

	// =============== testing if we can write in current directoy =====================
	if (home_dir == "")
	{
		try
		{
			BALL::String temp_file_name;
			BALL::File::createTemporaryFilename(temp_file_name);
			BALL::File out(temp_file_name, std::ios::out);
			out << "test" << std::endl;
			out.remove();
		}
		catch(...)
		{
			QMessageBox::warning(0, "Error while starting BALLView",
					QString("You dont have write access to the current working directory\n") +
					"and BALLView can not find your home directory. This can cause\n" +
					"unexpected behaviour. Please start BALLView from your homedir with\n" +
					"absolute path (e.g. C:\\Programs\\BALLView\\BALLView).\n");
		}
	}

	// =============== initialize Mainframe ============================================
	// Create the mainframe.
	BALL::Mainframe mainframe(0, "Mainframe");

	// can we use the users homedir as working dir?
	if (home_dir != "")
	{
		mainframe.setWorkingDir(home_dir);
	}

	// Register the mainfram (required for Python support).
	mainframe.setIdentifier("Mainframe");
	mainframe.registerThis();

	// Show the main window.
	mainframe.show();

	// =============== parsing command line arguments ==================================
	// If there are additional command line arguments, interpret them as files to open or logging flag.
	for (BALL::Index i = 1; i < argc; ++i)
	{
		BALL::String argument(argv[i]);
		if (argument == "-l")
		{
			mainframe.enableLoggingToFile();
			continue;
		}

		mainframe.openFile(argument);
	}

	// enable ending of program from python script
	if (mainframe.isAboutToQuit())
	{
		mainframe.aboutToExit();
		return 0;
	}

	// Remove the splashscreen
	splash->finish(&mainframe);
	delete splash;

  // Hand over control to the application.
  int value = application.exec();
	char*	return_value = getenv("BALL_RETURN_VALUE");
	if (return_value != 0)
	{
		try
		{
			value = BALL::String(return_value).toInt();
		}
		catch(...)
		{
		}
	}

	return value;
}
<commit_msg>Language support : correct formatting<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: main.C,v 1.20.8.3 2007/03/26 07:11:33 amoll Exp $
//

// order of includes is important: first qapplication, than BALL includes
#include <QtGui/qapplication.h>
#include <BALL/CONFIG/config.h>

#ifdef BALL_HAS_GLEW
#	include <GL/glew.h>
#endif

#include <QtCore/QLocale>
#include <QtCore/QTranslator>

#include <QtGui/qmessagebox.h>
#include <QtGui/QSplashScreen>
#include <QtOpenGL/qgl.h>

#include "mainframe.h"
#include <BALL/SYSTEM/path.h>
#include <BALL/SYSTEM/directory.h>
#include <BALL/FORMAT/INIFile.h>
#include <BALL/SYSTEM/fileSystem.h>
#include <BALL/COMMON/logStream.h>

#include <iostream>

#ifdef Q_WS_X11
#include <X11/Xlib.h>
#endif

void logMessages(QtMsgType type, const char *msg)
{
	BALL::String s(msg);
	if (s.hasPrefix("QTextBrowser")) return;

	switch ( type ) {
		case QtDebugMsg:
				BALL::Log.info() << msg << std::endl;
				break;
		case QtWarningMsg:
				BALL::Log.warn() << msg << std::endl;
				break;
		case QtFatalMsg:
				fprintf( stderr, "Fatal: %s\n", msg );
				abort();                    // deliberately core dump
		case QtCriticalMsg:
				fprintf( stderr, "Critical: %s\n", msg );
				abort();                    // deliberately core dump
	}
}

// uncomment this to use debugging to std::cout!
//#undef BALL_OS_WINDOWS

#ifndef BALL_OS_WINDOWS
int main(int argc, char **argv)
{
#else
int WINAPI WinMain(HINSTANCE, HINSTANCE, PSTR cmd_line, int)
{
	int argc = __argc;
	char** argv = __argv;
#endif

#ifdef Q_WS_X11
    XInitThreads();
#endif

	qInstallMsgHandler(logMessages);

	putenv("BALL_RETURN_VALUE=");
	QApplication application(argc, argv);

  QPixmap splash_pm(":BALLView-1.3-Splashscreen.png");
  QSplashScreen* splash = new QSplashScreen(splash_pm);
  splash->show();

	// =============== testing for opengl support ======================================
	if (!QGLFormat::hasOpenGL())
	{
		QMessageBox::critical(0, "Error while starting BALLView",
				"Your computer has no OpenGL support, please install the correct drivers. Aborting for now...",
				QMessageBox::Ok, Qt::NoButton, Qt::NoButton);
		return -1;
	}

	BALL::String home_dir = BALL::Directory::getUserHomeDir();

	// =============== load translations =====================
	BALL::INIFile f(home_dir + BALL::FileSystem::PATH_SEPARATOR + ".BALLView");
	f.read();

	if (f.hasEntry("GENERAL", "language"))
	{
		QString str = f.getValue("GENERAL", "language").c_str();

		if (!(str == "Default"))
		{
			QString loc = "BALLView." + str;

			BALL::Path p;
			QStringList dpaths = QString(p.getDataPath().c_str()).split("\n");

			QTranslator* translator = new QTranslator(&application);
			foreach(QString str, dpaths)
			{
				translator->load(loc, str + "BALLView/translations");
				if (!translator->isEmpty())
				{
					QCoreApplication::installTranslator(translator);
					break;
				}
			}
		}
	}

	// =============== testing if we can write in current directoy =====================
	if (home_dir == "")
	{
		try
		{
			BALL::String temp_file_name;
			BALL::File::createTemporaryFilename(temp_file_name);
			BALL::File out(temp_file_name, std::ios::out);
			out << "test" << std::endl;
			out.remove();
		}
		catch(...)
		{
			QMessageBox::warning(0, "Error while starting BALLView",
					QString("You dont have write access to the current working directory\n") +
					"and BALLView can not find your home directory. This can cause\n" +
					"unexpected behaviour. Please start BALLView from your homedir with\n" +
					"absolute path (e.g. C:\\Programs\\BALLView\\BALLView).\n");
		}
	}

	// =============== initialize Mainframe ============================================
	// Create the mainframe.
	BALL::Mainframe mainframe(0, "Mainframe");

	// can we use the users homedir as working dir?
	if (home_dir != "")
	{
		mainframe.setWorkingDir(home_dir);
	}

	// Register the mainfram (required for Python support).
	mainframe.setIdentifier("Mainframe");
	mainframe.registerThis();

	// Show the main window.
	mainframe.show();

	// =============== parsing command line arguments ==================================
	// If there are additional command line arguments, interpret them as files to open or logging flag.
	for (BALL::Index i = 1; i < argc; ++i)
	{
		BALL::String argument(argv[i]);
		if (argument == "-l")
		{
			mainframe.enableLoggingToFile();
			continue;
		}

		mainframe.openFile(argument);
	}

	// enable ending of program from python script
	if (mainframe.isAboutToQuit())
	{
		mainframe.aboutToExit();
		return 0;
	}

	// Remove the splashscreen
	splash->finish(&mainframe);
	delete splash;

  // Hand over control to the application.
  int value = application.exec();
	char*	return_value = getenv("BALL_RETURN_VALUE");
	if (return_value != 0)
	{
		try
		{
			value = BALL::String(return_value).toInt();
		}
		catch(...)
		{
		}
	}

	return value;
}
<|endoftext|>


<commit_before>#include <exception>

#include <gtest/gtest.h>

#include "range.h"

using namespace whoshuu;

TEST(RangeIntegerTests, ValueStopTest) {
    for (auto stop = 0; stop < 100; ++stop) {
        auto expected = 0;
        for (auto computed : range(stop)) {
            EXPECT_EQ(expected, computed);
            ++expected;
        }
    }
}

TEST(RangeIntegerTests, ValueStartStopTest) {
    for (auto start = -100; start < 100; ++start) {
        for (auto stop = start; stop < 100; ++stop) {
            auto expected = start;
            for (auto computed : range(start, stop)) {
                EXPECT_EQ(expected, computed);
                ++expected;
            }
        }
    }
}

TEST(RangeIntegerTests, ValueStartStopStepTest) {
    for (auto start = -100; start < 100; ++start) {
        for (auto stop = start; stop < 100; ++stop) {
            for (auto step = 1; step < 100; ++step) {
                auto expected = start;
                for (auto computed : range(start, stop, step)) {
                    EXPECT_EQ(expected, computed);
                    expected += step;
                }
            }
        }
    }
}

TEST(RangeIntegerTests, ValueStopReverseTest) {
    for (auto stop = 100; stop > 0; --stop) {
        auto expected = 100;
        for (auto computed : range(100, stop, -1)) {
            EXPECT_EQ(expected, computed);
            --expected;
        }
    }
}

TEST(RangeIntegerTests, ValueStartStopReverseTest) {
    for (auto start = 100; start > -100; --start) {
        for (auto stop = start; stop > -100; --stop) {
            auto expected = start;
            for (auto computed : range(start, stop, -1)) {
                EXPECT_EQ(expected, computed);
                --expected;
            }
        }
    }
}

TEST(RangeIntegerTests, ValueStartStopStepReverseTest) {
    for (auto start = 100; start > -100; --start) {
        for (auto stop = start; stop > -100; --stop) {
            for (auto step = -1; step > -100; --step) {
                auto expected = start;
                for (auto computed : range(start, stop, step)) {
                    EXPECT_EQ(expected, computed);
                    expected -= step;
                }
            }
        }
    }
}

TEST(RangeIntegerTests, ValueNegativeStopExceptionTest) {
    bool thrown = false;
    try {
        range(-10);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeIntegerTests, ValueStartLargerThanStopExceptionTest) {
    bool thrown = false;
    try {
        range(11, 10);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeIntegerTests, ValueStepWrongDirectionExceptionTest) {
    bool thrown = false;
    try {
        range(0, 10, -1);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeIntegerTests, ValueAnotherStepWrongDirectionExceptionTest) {
    bool thrown = false;
    try {
        range(10, 0, 1);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeIntegerTests, ValueZeroStepExceptionTest) {
    bool thrown = false;
    try {
        range(0, 10, 0);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range step argument must not be zero"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeFloatTests, ValueStopTest) {
    for (auto stop = 0.f; stop < 100.f; ++stop) {
        auto expected = 0.f;
        for (auto computed : range(stop)) {
            EXPECT_EQ(expected, computed);
            ++expected;
        }
    }
}

TEST(RangeFloatTests, ValueStartStopTest) {
    for (auto start = -100.f; start < 100.f; ++start) {
        for (auto stop = start; stop < 100.f; ++stop) {
            auto expected = start;
            for (auto computed : range(start, stop)) {
                EXPECT_EQ(expected, computed);
                ++expected;
            }
        }
    }
}

TEST(RangeFloatTests, ValueStartStopStepTest) {
    for (auto start = -100.f; start < 100.f; ++start) {
        for (auto stop = start; stop < 100.f; ++stop) {
            for (auto step = 1.5f; step < 100.f; ++step) {
                auto expected = start;
                for (auto computed : range(start, stop, step)) {
                    EXPECT_EQ(expected, computed);
                    expected += step;
                }
            }
        }
    }
}

TEST(RangeFloatTests, ValueStopReverseTest) {
    for (auto stop = 100.f; stop > 0.f; --stop) {
        auto expected = 100.f;
        for (auto computed : range(100.f, stop, -1.5f)) {
            EXPECT_EQ(expected, computed);
            --expected;
        }
    }
}

TEST(RangeFloatTests, ValueStartStopReverseTest) {
    for (auto start = 100.f; start > -100.f; --start) {
        for (auto stop = start; stop > -100.f; --stop) {
            auto expected = start;
            for (auto computed : range(start, stop, -1.5f)) {
                EXPECT_EQ(expected, computed);
                --expected;
            }
        }
    }
}

TEST(RangeFloatTests, ValueStartStopStepReverseTest) {
    for (auto start = 100.f; start > -100.f; --start) {
        for (auto stop = start; stop > -100.f; --stop) {
            for (auto step = -1.5f; step > -100.f; --step) {
                auto expected = start;
                for (auto computed : range(start, stop, step)) {
                    EXPECT_EQ(expected, computed);
                    expected -= step;
                }
            }
        }
    }
}

TEST(RangeFloatTests, ValueNegativeStopExceptionTest) {
    bool thrown = false;
    try {
        range(-10.f);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeFloatTests, ValueStartLargerThanStopExceptionTest) {
    bool thrown = false;
    try {
        range(11.f, 10.f);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeFloatTests, ValueStepWrongDirectionExceptionTest) {
    bool thrown = false;
    try {
        range(0.f, 10.f, -1.f);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeFloatTests, ValueAnotherStepWrongDirectionExceptionTest) {
    bool thrown = false;
    try {
        range(10.f, 0.f, 1.f);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeFloatTests, ValueZeroStepExceptionTest) {
    bool thrown = false;
    try {
        range(0.f, 10.f, 0.f);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range step argument must not be zero"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeDoubleTests, ValueStopTest) {
    for (auto stop = 0.; stop < 100.; ++stop) {
        auto expected = 0.;
        for (auto computed : range(stop)) {
            EXPECT_EQ(expected, computed);
            ++expected;
        }
    }
}

TEST(RangeDoubleTests, ValueStartStopTest) {
    for (auto start = -100.; start < 100.; ++start) {
        for (auto stop = start; stop < 100.; ++stop) {
            auto expected = start;
            for (auto computed : range(start, stop)) {
                EXPECT_EQ(expected, computed);
                ++expected;
            }
        }
    }
}

TEST(RangeDoubleTests, ValueStartStopStepTest) {
    for (auto start = -100.; start < 100.; ++start) {
        for (auto stop = start; stop < 100.; ++stop) {
            for (auto step = 1.5; step < 100.; ++step) {
                auto expected = start;
                for (auto computed : range(start, stop, step)) {
                    EXPECT_EQ(expected, computed);
                    expected += step;
                }
            }
        }
    }
}

TEST(RangeDoubleTests, ValueStopReverseTest) {
    for (auto stop = 100.; stop > 0.; --stop) {
        auto expected = 100.;
        for (auto computed : range(100., stop, -1.5)) {
            EXPECT_EQ(expected, computed);
            --expected;
        }
    }
}

TEST(RangeDoubleTests, ValueStartStopReverseTest) {
    for (auto start = 100.; start > -100.; --start) {
        for (auto stop = start; stop > -100.; --stop) {
            auto expected = start;
            for (auto computed : range(start, stop, -1.5)) {
                EXPECT_EQ(expected, computed);
                --expected;
            }
        }
    }
}

TEST(RangeDoubleTests, ValueStartStopStepReverseTest) {
    for (auto start = 100.; start > -100.; --start) {
        for (auto stop = start; stop > -100.; --stop) {
            for (auto step = -1.5; step > -100.; --step) {
                auto expected = start;
                for (auto computed : range(start, stop, step)) {
                    EXPECT_EQ(expected, computed);
                    expected -= step;
                }
            }
        }
    }
}

TEST(RangeDoubleTests, ValueNegativeStopExceptionTest) {
    bool thrown = false;
    try {
        range(-10.);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeDoubleTests, ValueStartLargerThanStopExceptionTest) {
    bool thrown = false;
    try {
        range(11., 10.);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeDoubleTests, ValueStepWrongDirectionExceptionTest) {
    bool thrown = false;
    try {
        range(0., 10., -1.);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeDoubleTests, ValueAnotherStepWrongDirectionExceptionTest) {
    bool thrown = false;
    try {
        range(10., 0., 1.);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeDoubleTests, ValueZeroStepExceptionTest) {
    bool thrown = false;
    try {
        range(0., 10., 0.);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range step argument must not be zero"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}
<commit_msg>Fix failing tests<commit_after>#include <exception>

#include <gtest/gtest.h>

#include "range.h"

using namespace whoshuu;

TEST(RangeIntegerTests, ValueStopTest) {
    for (auto stop = 0; stop < 100; ++stop) {
        auto expected = 0;
        for (auto computed : range(stop)) {
            EXPECT_EQ(expected, computed);
            ++expected;
        }
    }
}

TEST(RangeIntegerTests, ValueStartStopTest) {
    for (auto start = -100; start < 100; ++start) {
        for (auto stop = start; stop < 100; ++stop) {
            auto expected = start;
            for (auto computed : range(start, stop)) {
                EXPECT_EQ(expected, computed);
                ++expected;
            }
        }
    }
}

TEST(RangeIntegerTests, ValueStartStopStepTest) {
    for (auto start = -100; start < 100; ++start) {
        for (auto stop = start; stop < 100; ++stop) {
            for (auto step = 1; step < 100; ++step) {
                auto expected = start;
                for (auto computed : range(start, stop, step)) {
                    EXPECT_EQ(expected, computed);
                    expected += step;
                }
            }
        }
    }
}

TEST(RangeIntegerTests, ValueStopReverseTest) {
    for (auto stop = 100; stop > 0; --stop) {
        auto expected = 100;
        for (auto computed : range(100, stop, -1)) {
            EXPECT_EQ(expected, computed);
            --expected;
        }
    }
}

TEST(RangeIntegerTests, ValueStartStopReverseTest) {
    for (auto start = 100; start > -100; --start) {
        for (auto stop = start; stop > -100; --stop) {
            auto expected = start;
            for (auto computed : range(start, stop, -1)) {
                EXPECT_EQ(expected, computed);
                --expected;
            }
        }
    }
}

TEST(RangeIntegerTests, ValueStartStopStepReverseTest) {
    for (auto start = 100; start > -100; --start) {
        for (auto stop = start; stop > -100; --stop) {
            for (auto step = -1; step > -100; --step) {
                auto expected = start;
                for (auto computed : range(start, stop, step)) {
                    EXPECT_EQ(expected, computed);
                    expected += step;
                }
            }
        }
    }
}

TEST(RangeIntegerTests, ValueNegativeStopExceptionTest) {
    bool thrown = false;
    try {
        range(-10);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeIntegerTests, ValueStartLargerThanStopExceptionTest) {
    bool thrown = false;
    try {
        range(11, 10);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeIntegerTests, ValueStepWrongDirectionExceptionTest) {
    bool thrown = false;
    try {
        range(0, 10, -1);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeIntegerTests, ValueAnotherStepWrongDirectionExceptionTest) {
    bool thrown = false;
    try {
        range(10, 0, 1);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeIntegerTests, ValueZeroStepExceptionTest) {
    bool thrown = false;
    try {
        range(0, 10, 0);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range step argument must not be zero"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeFloatTests, ValueStopTest) {
    for (auto stop = 0.f; stop < 100.f; ++stop) {
        auto expected = 0.f;
        for (auto computed : range(stop)) {
            EXPECT_EQ(expected, computed);
            ++expected;
        }
    }
}

TEST(RangeFloatTests, ValueStartStopTest) {
    for (auto start = -100.f; start < 100.f; ++start) {
        for (auto stop = start; stop < 100.f; ++stop) {
            auto expected = start;
            for (auto computed : range(start, stop)) {
                EXPECT_EQ(expected, computed);
                ++expected;
            }
        }
    }
}

TEST(RangeFloatTests, ValueStartStopStepTest) {
    for (auto start = -100.f; start < 100.f; ++start) {
        for (auto stop = start; stop < 100.f; ++stop) {
            for (auto step = 1.5f; step < 100.f; ++step) {
                auto expected = start;
                for (auto computed : range(start, stop, step)) {
                    EXPECT_EQ(expected, computed);
                    expected += step;
                }
            }
        }
    }
}

TEST(RangeFloatTests, ValueStopReverseTest) {
    for (auto stop = 100.f; stop > 0.f; --stop) {
        auto expected = 100.f;
        for (auto computed : range(100.f, stop, -1.5f)) {
            EXPECT_EQ(expected, computed);
            expected -= 1.5f;
        }
    }
}

TEST(RangeFloatTests, ValueStartStopReverseTest) {
    for (auto start = 100.f; start > -100.f; --start) {
        for (auto stop = start; stop > -100.f; --stop) {
            auto expected = start;
            for (auto computed : range(start, stop, -1.5f)) {
                EXPECT_EQ(expected, computed);
                expected -= 1.5f;
            }
        }
    }
}

TEST(RangeFloatTests, ValueStartStopStepReverseTest) {
    for (auto start = 100.f; start > -100.f; --start) {
        for (auto stop = start; stop > -100.f; --stop) {
            for (auto step = -1.5f; step > -100.f; --step) {
                auto expected = start;
                for (auto computed : range(start, stop, step)) {
                    EXPECT_EQ(expected, computed);
                    expected += step;
                }
            }
        }
    }
}

TEST(RangeFloatTests, ValueNegativeStopExceptionTest) {
    bool thrown = false;
    try {
        range(-10.f);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeFloatTests, ValueStartLargerThanStopExceptionTest) {
    bool thrown = false;
    try {
        range(11.f, 10.f);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeFloatTests, ValueStepWrongDirectionExceptionTest) {
    bool thrown = false;
    try {
        range(0.f, 10.f, -1.f);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeFloatTests, ValueAnotherStepWrongDirectionExceptionTest) {
    bool thrown = false;
    try {
        range(10.f, 0.f, 1.f);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeFloatTests, ValueZeroStepExceptionTest) {
    bool thrown = false;
    try {
        range(0.f, 10.f, 0.f);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range step argument must not be zero"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeDoubleTests, ValueStopTest) {
    for (auto stop = 0.; stop < 100.; ++stop) {
        auto expected = 0.;
        for (auto computed : range(stop)) {
            EXPECT_EQ(expected, computed);
            ++expected;
        }
    }
}

TEST(RangeDoubleTests, ValueStartStopTest) {
    for (auto start = -100.; start < 100.; ++start) {
        for (auto stop = start; stop < 100.; ++stop) {
            auto expected = start;
            for (auto computed : range(start, stop)) {
                EXPECT_EQ(expected, computed);
                ++expected;
            }
        }
    }
}

TEST(RangeDoubleTests, ValueStartStopStepTest) {
    for (auto start = -100.; start < 100.; ++start) {
        for (auto stop = start; stop < 100.; ++stop) {
            for (auto step = 1.5; step < 100.; ++step) {
                auto expected = start;
                for (auto computed : range(start, stop, step)) {
                    EXPECT_EQ(expected, computed);
                    expected += step;
                }
            }
        }
    }
}

TEST(RangeDoubleTests, ValueStopReverseTest) {
    for (auto stop = 100.; stop > 0.; --stop) {
        auto expected = 100.;
        for (auto computed : range(100., stop, -1.5)) {
            EXPECT_EQ(expected, computed);
            expected -= 1.5;
        }
    }
}

TEST(RangeDoubleTests, ValueStartStopReverseTest) {
    for (auto start = 100.; start > -100.; --start) {
        for (auto stop = start; stop > -100.; --stop) {
            auto expected = start;
            for (auto computed : range(start, stop, -1.5)) {
                EXPECT_EQ(expected, computed);
                expected -= 1.5;
            }
        }
    }
}

TEST(RangeDoubleTests, ValueStartStopStepReverseTest) {
    for (auto start = 100.; start > -100.; --start) {
        for (auto stop = start; stop > -100.; --stop) {
            for (auto step = -1.5; step > -100.; --step) {
                auto expected = start;
                for (auto computed : range(start, stop, step)) {
                    EXPECT_EQ(expected, computed);
                    expected += step;
                }
            }
        }
    }
}

TEST(RangeDoubleTests, ValueNegativeStopExceptionTest) {
    bool thrown = false;
    try {
        range(-10.);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeDoubleTests, ValueStartLargerThanStopExceptionTest) {
    bool thrown = false;
    try {
        range(11., 10.);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeDoubleTests, ValueStepWrongDirectionExceptionTest) {
    bool thrown = false;
    try {
        range(0., 10., -1.);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeDoubleTests, ValueAnotherStepWrongDirectionExceptionTest) {
    bool thrown = false;
    try {
        range(10., 0., 1.);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range arguments must result in termination"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}

TEST(RangeDoubleTests, ValueZeroStepExceptionTest) {
    bool thrown = false;
    try {
        range(0., 10., 0.);
    } catch (const std::invalid_argument& e) {
        thrown = true;
        EXPECT_EQ(std::string{"Range step argument must not be zero"},
                  std::string{e.what()});
    }
    EXPECT_TRUE(thrown);
}
<|endoftext|>


<commit_before>#include "gigasecond.h"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>

// See <http://www.boost.org/doc/libs/1_59_0/doc/html/date_time/posix_time.html>
// for documentation on boost::posix_time

using namespace boost::posix_time;

BOOST_AUTO_TEST_CASE(test_1)
{
    const ptime actual = gigasecond::advance(time_from_string("2011-04-25 00:00:00"));

    const ptime expected(time_from_string("2043-01-01 01:46:40"));
    BOOST_REQUIRE_EQUAL(expected, actual);
}

#if defined(EXERCISM_RUN_ALL_TESTS)
BOOST_AUTO_TEST_CASE(test_2)
{
    const auto actual = gigasecond::advance(time_from_string("1977-06-13 00:00:00"));

    const ptime expected(time_from_string("2009-02-19 01:46:40"));
    BOOST_REQUIRE_EQUAL(expected, actual);
}

BOOST_AUTO_TEST_CASE(test_3)
{
    const auto actual = gigasecond::advance(time_from_string("1959-07-19 00:00:00"));

    const ptime expected(time_from_string("1991-03-27 01:46:40"));
    BOOST_REQUIRE_EQUAL(expected, actual);
}

BOOST_AUTO_TEST_CASE(test_4)
{
    const auto actual = gigasecond::advance(time_from_string("2015-01-24 22:00:00"));

    const ptime expected(time_from_string("2046-10-02 23:46:40"));
    BOOST_REQUIRE_EQUAL(expected, actual);
}

BOOST_AUTO_TEST_CASE(test_5)
{
    const auto actual = gigasecond::advance(time_from_string("2015-01-24 23:59:59"));

    const ptime expected(time_from_string("2046-10-03 01:46:39"));
    BOOST_REQUIRE_EQUAL(expected, actual);
}
#endif
<commit_msg>including neded boost posix_time (#201)<commit_after>#include "gigasecond.h"
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include "boost/date_time/posix_time/posix_time.hpp"

// See <http://www.boost.org/doc/libs/1_59_0/doc/html/date_time/posix_time.html>
// for documentation on boost::posix_time

using namespace boost::posix_time;

BOOST_AUTO_TEST_CASE(test_1)
{
    const ptime actual = gigasecond::advance(time_from_string("2011-04-25 00:00:00"));

    const ptime expected(time_from_string("2043-01-01 01:46:40"));
    BOOST_REQUIRE_EQUAL(expected, actual);
}

#if defined(EXERCISM_RUN_ALL_TESTS)
BOOST_AUTO_TEST_CASE(test_2)
{
    const auto actual = gigasecond::advance(time_from_string("1977-06-13 00:00:00"));

    const ptime expected(time_from_string("2009-02-19 01:46:40"));
    BOOST_REQUIRE_EQUAL(expected, actual);
}

BOOST_AUTO_TEST_CASE(test_3)
{
    const auto actual = gigasecond::advance(time_from_string("1959-07-19 00:00:00"));

    const ptime expected(time_from_string("1991-03-27 01:46:40"));
    BOOST_REQUIRE_EQUAL(expected, actual);
}

BOOST_AUTO_TEST_CASE(test_4)
{
    const auto actual = gigasecond::advance(time_from_string("2015-01-24 22:00:00"));

    const ptime expected(time_from_string("2046-10-02 23:46:40"));
    BOOST_REQUIRE_EQUAL(expected, actual);
}

BOOST_AUTO_TEST_CASE(test_5)
{
    const auto actual = gigasecond::advance(time_from_string("2015-01-24 23:59:59"));

    const ptime expected(time_from_string("2046-10-03 01:46:39"));
    BOOST_REQUIRE_EQUAL(expected, actual);
}
#endif
<|endoftext|>


<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: colorProcessor.C,v 1.5 2003/10/17 16:17:37 amoll Exp $

#include <BALL/VIEW/MODELS/colorProcessor.h>
#include <BALL/VIEW/DATATYPE/colorExtension2.h>
#include <BALL/KERNEL/bond.h>

using namespace std;

namespace BALL
{
	namespace VIEW
	{

ColorProcessor::ColorProcessor()
	throw()
	:	UnaryProcessor<GeometricObject*>()
{
	clear();
}

ColorProcessor::ColorProcessor(const ColorProcessor& color_Processor)
	throw()
	:	UnaryProcessor<GeometricObject*>(color_Processor),
		default_color_(color_Processor.default_color_)
{
}

ColorProcessor::~ColorProcessor()
{
	#ifdef BALL_VIEW_DEBUG
		Log.error() << "Destructing object " << (void *)this
								<< " of class " << RTTI::getName<ColorProcessor>() << std::endl;
	#endif
}

void ColorProcessor::clear()
	throw()
{
	default_color_.set("FF0000FF");
}

void ColorProcessor::set(const ColorProcessor& color_Processor)
	throw()
{
	default_color_ = color_Processor.default_color_;
}

const ColorProcessor& ColorProcessor::operator = (const ColorProcessor& color_Processor)
	throw()
{
	set(color_Processor);
	return *this;
}

void ColorProcessor::swap(ColorProcessor& color_Processor)
	throw()
{
	default_color_.swap(color_Processor.default_color_);
}

void ColorProcessor::dump(ostream& s, Size depth) const
	throw()
{
	BALL_DUMP_STREAM_PREFIX(s);

	BALL_DUMP_DEPTH(s, depth);
	BALL_DUMP_HEADER(s, this, this);

	BALL_DUMP_DEPTH(s, depth);
	s << "default_color: " << default_color_ << endl;

	BALL_DUMP_STREAM_SUFFIX(s);
}

Processor::Result ColorProcessor::operator() (GeometricObject*& object)
{
	if (object->getComposite() == 0)
	{
		object->setColor(default_color_);
		return Processor::CONTINUE;
	}

	if (!RTTI::isKindOf<ColorExtension2>(*object))
	{
		object->setColor(getColor(object->getComposite()));
		return Processor::CONTINUE;
	}

	if (RTTI::isKindOf<Bond>(*object->getComposite()))
	{
		Bond* bond = (Bond*) object->getComposite();
		object->setColor(getColor(bond->getFirstAtom()));
		((ColorExtension2*)object)->setColor2(getColor(bond->getSecondAtom()));
	}
	else
	{
		ColorRGBA color = getColor(object->getComposite());
		object->setColor(color);
		((ColorExtension2*)object)->setColor2(color);
	}
	return Processor::CONTINUE;
}

} } // namespaces
<commit_msg>fixed problem with cast in operator ()<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: colorProcessor.C,v 1.6 2003/10/18 10:22:43 amoll Exp $

#include <BALL/VIEW/MODELS/colorProcessor.h>
#include <BALL/VIEW/DATATYPE/colorExtension2.h>
#include <BALL/KERNEL/bond.h>

using namespace std;

namespace BALL
{
	namespace VIEW
	{

ColorProcessor::ColorProcessor()
	throw()
	:	UnaryProcessor<GeometricObject*>()
{
	clear();
}

ColorProcessor::ColorProcessor(const ColorProcessor& color_Processor)
	throw()
	:	UnaryProcessor<GeometricObject*>(color_Processor),
		default_color_(color_Processor.default_color_)
{
}

ColorProcessor::~ColorProcessor()
{
	#ifdef BALL_VIEW_DEBUG
		Log.error() << "Destructing object " << (void *)this
								<< " of class " << RTTI::getName<ColorProcessor>() << std::endl;
	#endif
}

void ColorProcessor::clear()
	throw()
{
	default_color_.set("FF0000FF");
}

void ColorProcessor::set(const ColorProcessor& color_Processor)
	throw()
{
	default_color_ = color_Processor.default_color_;
}

const ColorProcessor& ColorProcessor::operator = (const ColorProcessor& color_Processor)
	throw()
{
	set(color_Processor);
	return *this;
}

void ColorProcessor::swap(ColorProcessor& color_Processor)
	throw()
{
	default_color_.swap(color_Processor.default_color_);
}

void ColorProcessor::dump(ostream& s, Size depth) const
	throw()
{
	BALL_DUMP_STREAM_PREFIX(s);

	BALL_DUMP_DEPTH(s, depth);
	BALL_DUMP_HEADER(s, this, this);

	BALL_DUMP_DEPTH(s, depth);
	s << "default_color: " << default_color_ << endl;

	BALL_DUMP_STREAM_SUFFIX(s);
}

Processor::Result ColorProcessor::operator() (GeometricObject*& object)
{
	if (object->getComposite() == 0)
	{
		object->setColor(default_color_);
		if (RTTI::isKindOf<ColorExtension2>(*object))
		{
			ColorExtension2* two_colored = dynamic_cast<ColorExtension2*>(object);
			two_colored->setColor2(default_color_);
		}
		return Processor::CONTINUE;
	}

	if (!RTTI::isKindOf<ColorExtension2>(*object))
	{
		object->setColor(getColor(object->getComposite()));
		return Processor::CONTINUE;
	}

	// ok, we have a two colored object
	ColorExtension2* two_colored = dynamic_cast<ColorExtension2*>(object);
	if (RTTI::isKindOf<Bond>(*object->getComposite()))
	{
		Bond* bond = (Bond*) object->getComposite();
		object->setColor(getColor(bond->getFirstAtom()));
		two_colored->setColor2(getColor(bond->getSecondAtom()));
	}
	else
	{
		ColorRGBA color = getColor(object->getComposite());
		object->setColor(color);
		two_colored->setColor2(color);
	}
	return Processor::CONTINUE;
}

} } // namespaces
<|endoftext|>


<commit_before><commit_msg>Adicionado exercício 1069<commit_after><|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen 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.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void stable_norm(const MatrixType& m)
{
  /* this test covers the following files:
     StableNorm.h
  */

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;

  int rows = m.rows();
  int cols = m.cols();

  Scalar big = ei_random<Scalar>() * std::numeric_limits<RealScalar>::max() * 1e-4;
  Scalar small = 1/big;

  MatrixType  vzero = MatrixType::Zero(rows, cols),
              vrand = MatrixType::Random(rows, cols),
              vbig(rows, cols),
              vsmall(rows,cols);

  vbig.fill(big);
  vsmall.fill(small);

  VERIFY_IS_MUCH_SMALLER_THAN(vzero.norm(), static_cast<RealScalar>(1));
  VERIFY_IS_APPROX(vrand.stableNorm(),      vrand.norm());
  VERIFY_IS_APPROX(vrand.blueNorm(),        vrand.norm());
  VERIFY_IS_APPROX(vrand.hypotNorm(),       vrand.norm());

  RealScalar size = m.size();

  // test overflow
  VERIFY_IS_NOT_APPROX(vbig.norm(),   ei_sqrt(size)*big); // here the default norm must fail
  VERIFY_IS_APPROX(vbig.stableNorm(), ei_sqrt(size)*big);
  VERIFY_IS_APPROX(vbig.blueNorm(),   ei_sqrt(size)*big);
  VERIFY_IS_APPROX(vbig.hypotNorm(),  ei_sqrt(size)*big);

  // test underflow
  VERIFY_IS_NOT_APPROX(vsmall.norm(),   ei_sqrt(size)*small); // here the default norm must fail
  VERIFY_IS_APPROX(vsmall.stableNorm(), ei_sqrt(size)*small);
  VERIFY_IS_APPROX(vsmall.blueNorm(),   ei_sqrt(size)*small);
  VERIFY_IS_APPROX(vsmall.hypotNorm(),  ei_sqrt(size)*small);
}

void test_stable_norm()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST( stable_norm(Matrix<float, 1, 1>()) );
    CALL_SUBTEST( stable_norm(Vector4d()) );
    CALL_SUBTEST( stable_norm(VectorXd(ei_random<int>(10,2000))) );
    CALL_SUBTEST( stable_norm(VectorXf(ei_random<int>(10,2000))) );
    CALL_SUBTEST( stable_norm(VectorXcd(ei_random<int>(10,2000))) );
  }
}

<commit_msg>Added missing casts.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen 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.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void stable_norm(const MatrixType& m)
{
  /* this test covers the following files:
     StableNorm.h
  */

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;

  int rows = m.rows();
  int cols = m.cols();

  Scalar big = ei_random<Scalar>() * std::numeric_limits<RealScalar>::max() * RealScalar(1e-4);
  Scalar small = static_cast<RealScalar>(1)/big;

  MatrixType  vzero = MatrixType::Zero(rows, cols),
              vrand = MatrixType::Random(rows, cols),
              vbig(rows, cols),
              vsmall(rows,cols);

  vbig.fill(big);
  vsmall.fill(small);

  VERIFY_IS_MUCH_SMALLER_THAN(vzero.norm(), static_cast<RealScalar>(1));
  VERIFY_IS_APPROX(vrand.stableNorm(),      vrand.norm());
  VERIFY_IS_APPROX(vrand.blueNorm(),        vrand.norm());
  VERIFY_IS_APPROX(vrand.hypotNorm(),       vrand.norm());

  RealScalar size = static_cast<RealScalar>(m.size());

  // test overflow
  VERIFY_IS_NOT_APPROX(static_cast<Scalar>(vbig.norm()),   ei_sqrt(size)*big); // here the default norm must fail
  VERIFY_IS_APPROX(static_cast<Scalar>(vbig.stableNorm()), ei_sqrt(size)*big);
  VERIFY_IS_APPROX(static_cast<Scalar>(vbig.blueNorm()),   ei_sqrt(size)*big);
  VERIFY_IS_APPROX(static_cast<Scalar>(vbig.hypotNorm()),  ei_sqrt(size)*big);

  // test underflow
  VERIFY_IS_NOT_APPROX(static_cast<Scalar>(vsmall.norm()),   ei_sqrt(size)*small); // here the default norm must fail
  VERIFY_IS_APPROX(static_cast<Scalar>(vsmall.stableNorm()), ei_sqrt(size)*small);
  VERIFY_IS_APPROX(static_cast<Scalar>(vsmall.blueNorm()),   ei_sqrt(size)*small);
  VERIFY_IS_APPROX(static_cast<Scalar>(vsmall.hypotNorm()),  ei_sqrt(size)*small);
}

void test_stable_norm()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST( stable_norm(Matrix<float, 1, 1>()) );
    CALL_SUBTEST( stable_norm(Vector4d()) );
    CALL_SUBTEST( stable_norm(VectorXd(ei_random<int>(10,2000))) );
    CALL_SUBTEST( stable_norm(VectorXf(ei_random<int>(10,2000))) );
    CALL_SUBTEST( stable_norm(VectorXcd(ei_random<int>(10,2000))) );
  }
}
<|endoftext|>


<commit_before>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

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

This program 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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
channel `#navitia` on riot https://riot.im/app/#/room/#navitia:matrix.org
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "astar_path_finder.h"
#include "visitor.h"

#include <boost/graph/astar_search.hpp>
#include <boost/graph/filtered_graph.hpp>

namespace navitia {
namespace georef {

AstarPathFinder::~AstarPathFinder() = default;

void AstarPathFinder::init(const type::GeographicalCoord& start_coord,
                           const type::GeographicalCoord& dest_projected_coord,
                           nt::Mode_e mode,
                           const float speed_factor) {
    PathFinder::init_start(start_coord, mode, speed_factor);

    // we initialize the costs to the maximum value
    size_t n = boost::num_vertices(geo_ref.graph);
    costs.assign(n, bt::pos_infin);

    if (starting_edge.found) {
        costs.at(starting_edge[source_e]) =
            compute_cost_from_starting_edge_to_dist(starting_edge[source_e], dest_projected_coord);
        costs.at(starting_edge[target_e]) =
            compute_cost_from_starting_edge_to_dist(starting_edge[target_e], dest_projected_coord);
    }
}

void AstarPathFinder::start_distance_or_target_astar(const navitia::time_duration& radius,
                                                     const type::GeographicalCoord& dest_projected,
                                                     const std::vector<vertex_t>& destinations) {
    if (!starting_edge.found)
        return;
    computation_launch = true;
    // We start astar from source and target nodes
    try {
        astar({starting_edge[source_e], starting_edge[target_e]},
              astar_distance_heuristic(geo_ref.graph, dest_projected, 1. / double(default_speed[mode])),
              astar_distance_or_target_visitor(radius, distances, destinations));
    } catch (DestinationFound&) {
    }
}

/**
 * Launch an astar without initializing the data structure
 * Warning, it modifies the distances and the predecessors
 **/
void AstarPathFinder::astar(const std::array<georef::vertex_t, 2>& origin_vertexes,
                            const astar_distance_heuristic& heuristic,
                            const astar_distance_or_target_visitor& visitor) {
    // Note: the predecessors have been updated in init

    // Fill color map in white before A*
    std::fill(color.data.get(), color.data.get() + (color.n + color.elements_per_char - 1) / color.elements_per_char,
              0);

    // we filter the graph to only use certain mean of transport
    using filtered_graph = boost::filtered_graph<georef::Graph, boost::keep_all, TransportationModeFilter>;
    auto g = filtered_graph(geo_ref.graph, {}, TransportationModeFilter(mode, geo_ref));
    auto weight_map = boost::get(&Edge::duration, geo_ref.graph);
    auto combiner = SpeedDistanceCombiner(speed_factor);

    astar_shortest_paths_no_init_with_heap(g, origin_vertexes.front(), origin_vertexes.back(), heuristic, visitor,
                                           weight_map, combiner);
}

template <class Graph, class WeightMap, class Compare>
void AstarPathFinder::astar_shortest_paths_no_init_with_heap(const Graph& g,
                                                             const vertex_t& s_begin,
                                                             const vertex_t& s_end,
                                                             const astar_distance_heuristic& h,
                                                             const astar_distance_or_target_visitor& vis,
                                                             const WeightMap& weight,
                                                             const SpeedDistanceCombiner& combine,
                                                             const Compare& compare) {
    typedef boost::d_ary_heap_indirect<vertex_t, 4, vertex_t*, navitia::time_duration*, Compare> MutableQueue;
    MutableQueue Q(&costs[0], &index_in_heap_map[0], compare);

    boost::detail::astar_bfs_visitor<astar_distance_heuristic, astar_distance_or_target_visitor, MutableQueue,
                                     vertex_t*, navitia::time_duration*, navitia::time_duration*, WeightMap,
                                     boost::two_bit_color_map<>, SpeedDistanceCombiner, Compare>
        bfs_vis(h, vis, Q, &predecessors[0], &costs[0], &distances[0], weight, color, combine, compare,
                navitia::seconds(0));

    breadth_first_visit(g, &s_begin, &s_end, Q, bfs_vis, color);
}

// The cost of a starting edge is the distance from this edge to the projected destination point (distance_to_dest)
// Plus the distance from this edge to the projected starting point (distances[v])
navitia::time_duration AstarPathFinder::compute_cost_from_starting_edge_to_dist(
    const vertex_t& v,
    const type::GeographicalCoord& dest_coord) const {
    auto const& edge_coords = geo_ref.graph[v].coord;
    auto const distance_to_dest = edge_coords.distance_to(dest_coord);
    return navitia::seconds(distance_to_dest / double(default_speed[mode] * speed_factor)) + distances[v];
}

}  // namespace georef
}  // namespace navitia
<commit_msg>Revert "[Kraken] Fix A* heuristic cost"<commit_after>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

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

This program 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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
channel `#navitia` on riot https://riot.im/app/#/room/#navitia:matrix.org
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "astar_path_finder.h"
#include "visitor.h"

#include <boost/graph/astar_search.hpp>
#include <boost/graph/filtered_graph.hpp>

namespace navitia {
namespace georef {

AstarPathFinder::~AstarPathFinder() = default;

void AstarPathFinder::init(const type::GeographicalCoord& start_coord,
                           const type::GeographicalCoord& dest_projected_coord,
                           nt::Mode_e mode,
                           const float speed_factor) {
    PathFinder::init_start(start_coord, mode, speed_factor);

    // we initialize the costs to the maximum value
    size_t n = boost::num_vertices(geo_ref.graph);
    costs.assign(n, bt::pos_infin);

    if (starting_edge.found) {
        costs.at(starting_edge[source_e]) =
            compute_cost_from_starting_edge_to_dist(starting_edge[source_e], dest_projected_coord);
        costs.at(starting_edge[target_e]) =
            compute_cost_from_starting_edge_to_dist(starting_edge[target_e], dest_projected_coord);
    }
}

void AstarPathFinder::start_distance_or_target_astar(const navitia::time_duration& radius,
                                                     const type::GeographicalCoord& dest_projected,
                                                     const std::vector<vertex_t>& destinations) {
    if (!starting_edge.found)
        return;
    computation_launch = true;
    // We start astar from source and target nodes
    try {
        astar({starting_edge[source_e], starting_edge[target_e]},
              astar_distance_heuristic(geo_ref.graph, dest_projected, 1. / double(default_speed[mode] * speed_factor)),
              astar_distance_or_target_visitor(radius, distances, destinations));
    } catch (DestinationFound&) {
    }
}

/**
 * Launch an astar without initializing the data structure
 * Warning, it modifies the distances and the predecessors
 **/
void AstarPathFinder::astar(const std::array<georef::vertex_t, 2>& origin_vertexes,
                            const astar_distance_heuristic& heuristic,
                            const astar_distance_or_target_visitor& visitor) {
    // Note: the predecessors have been updated in init

    // Fill color map in white before A*
    std::fill(color.data.get(), color.data.get() + (color.n + color.elements_per_char - 1) / color.elements_per_char,
              0);

    // we filter the graph to only use certain mean of transport
    using filtered_graph = boost::filtered_graph<georef::Graph, boost::keep_all, TransportationModeFilter>;
    auto g = filtered_graph(geo_ref.graph, {}, TransportationModeFilter(mode, geo_ref));
    auto weight_map = boost::get(&Edge::duration, geo_ref.graph);
    auto combiner = SpeedDistanceCombiner(speed_factor);

    astar_shortest_paths_no_init_with_heap(g, origin_vertexes.front(), origin_vertexes.back(), heuristic, visitor,
                                           weight_map, combiner);
}

template <class Graph, class WeightMap, class Compare>
void AstarPathFinder::astar_shortest_paths_no_init_with_heap(const Graph& g,
                                                             const vertex_t& s_begin,
                                                             const vertex_t& s_end,
                                                             const astar_distance_heuristic& h,
                                                             const astar_distance_or_target_visitor& vis,
                                                             const WeightMap& weight,
                                                             const SpeedDistanceCombiner& combine,
                                                             const Compare& compare) {
    typedef boost::d_ary_heap_indirect<vertex_t, 4, vertex_t*, navitia::time_duration*, Compare> MutableQueue;
    MutableQueue Q(&costs[0], &index_in_heap_map[0], compare);

    boost::detail::astar_bfs_visitor<astar_distance_heuristic, astar_distance_or_target_visitor, MutableQueue,
                                     vertex_t*, navitia::time_duration*, navitia::time_duration*, WeightMap,
                                     boost::two_bit_color_map<>, SpeedDistanceCombiner, Compare>
        bfs_vis(h, vis, Q, &predecessors[0], &costs[0], &distances[0], weight, color, combine, compare,
                navitia::seconds(0));

    breadth_first_visit(g, &s_begin, &s_end, Q, bfs_vis, color);
}

// The cost of a starting edge is the distance from this edge to the projected destination point (distance_to_dest)
// Plus the distance from this edge to the projected starting point (distances[v])
navitia::time_duration AstarPathFinder::compute_cost_from_starting_edge_to_dist(
    const vertex_t& v,
    const type::GeographicalCoord& dest_coord) const {
    auto const& edge_coords = geo_ref.graph[v].coord;
    auto const distance_to_dest = edge_coords.distance_to(dest_coord);
    return navitia::seconds(distance_to_dest / double(default_speed[mode] * speed_factor)) + distances[v];
}

}  // namespace georef
}  // namespace navitia
<|endoftext|>