Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
3 mathematical challenge_code
1. 1C:my_docsvirtual_machinesvmware_playershared_foldergeneral3_mathematical_challenge_code.cpp
/*
* monkey_puzzle.cpp
*
* Created on: 29 Jun 2014
* Author: Russell John Childs
*/
//=======================================================================================================
// COPYRIGHT NOTICE
// This code sample and ideas embodied remain the property of Dr Russell John Childs, PhD, and have been
// distributed as a representative example of my use of C++11 features,
//==========================================================================================================
============
#include <iostream>
#include <iomanip>
#include <string>
#include <set>
#include <vector>
#include <algorithm>
#include <functional>
//The answer to the riddle is 102485.
//General "point" class that accepts a metric defining the "distance" associatated with the interval between
two points.
// It is debatable whether it is good design practice to tie a metric to a point, but it provides for type-
safety in
// not allowing two points with different metrics to be used to calculate the interval.
template<typename Metric>
class Point
{
public:
//Simple ctor that sepcifies coords
explicit Point(int x, int y) :
m_x(x),
m_y(y),
m_is_accessible(true)
{
}
//NOP dtor
~Point(void)
{
}
//Function to calculate vector difference
friend Point operator-(const Point& lhs, const Point& rhs)
{
return Point(lhs.m_x - rhs.m_x, lhs.m_y - rhs.m_y);
}
//Function that calculates radial distance from origin according to the specified metric.
unsigned radius(void) const
{
return Metric()(*this);
}
//Binary predicate to be used by a sorted container to sort points by radial distance from origin
friend bool operator<(const Point& lhs, const Point& rhs)
{
//Sort by radial distance from origin, then by x, then by y.
return lhs.radius() < rhs.radius() ||
(lhs.radius() == rhs.radius() && lhs.m_x < rhs.m_x) ||
(lhs.radius() == rhs.radius() && lhs.m_x == rhs.m_x && lhs.m_y < rhs.m_y);
}
private:
friend Metric;
friend class SolveMonkeyPuzzle;
int m_x;
int m_y;
bool m_is_accessible;
};
2. 2C:my_docsvirtual_machinesvmware_playershared_foldergeneral3_mathematical_challenge_code.cpp
//==================
//Monkey's Metric = sum(abs(digit(x))) + sum(abs(digit(y)))
//==========
class MonkeyMetric
{
public:
//Default Ctor
MonkeyMetric(void)
{
}
//NOP Dtor
~MonkeyMetric(void)
{
}
//operator()
// returns the distance between points using the monkey metric. By default, it resturns distance of
point from origin.
unsigned operator()(const Point<MonkeyMetric>& lhs, const Point<MonkeyMetric>& rhs = Point<MonkeyMetric>
(0,0))
{
//Lmabda computes sum(abs(digit(value)))
auto sum_digits = [](unsigned value)
{
unsigned sum = 0;
for (auto digit : std::to_string(value))
{
sum += std::stoul(std::string(1,digit));
}
return sum;
};
return sum_digits(std::abs((lhs - rhs).m_x)) + sum_digits(std::abs((lhs - rhs).m_y));
}
};
//==================
//The solver class. Uses a counting method and a sorting method to compute number of points
// accessible to the monkey for a given value for the maximum radius from the origin.
//==========
class SolveMonkeyPuzzle
{
public:
//Ctor - takes as argument the maximum radial distance from origin the monkey may travel.
explicit SolveMonkeyPuzzle(unsigned bounds) :
m_bounds(bounds),
m_dmax(0),
m_parent_level{ 1, Point<MonkeyMetric>(0,0) }
{
//Compute the number of points that can be visited along X without exceeding
//the maximum radial distacne from the origin
while (Point<MonkeyMetric>(m_dmax, 0).radius() <= bounds)
{
++m_dmax;
}
--m_dmax; //correction for overshoot.
}
//NOP Dtor
~SolveMonkeyPuzzle(void)
{
}
//Accessor function for maximum number of points along X
unsigned get_dmax(void) const
{
return m_dmax;
}
//This function simply creates a grid quadrant (0, d_max) by (0, d_max)
// iterates over all points in this quadrant, adding them to a sorted set.
// Finally it returns the number of sorted points whose radial distance from
3. 3C:my_docsvirtual_machinesvmware_playershared_foldergeneral3_mathematical_challenge_code.cpp
// the origin is <= maximum.
unsigned get_sorted_count(void)
{
std::set<Point<MonkeyMetric>> points;
for (unsigned x = 0; x <= m_dmax; ++x)
{
for (unsigned y = 0; y <= m_dmax; ++y)
{
points.insert(Point<MonkeyMetric>(x, y));
}
}
/*if (m_bounds == 1)
{
for (auto& point : points)
{
std::cout << "Point(" << point.m_x << "," << point.m_y << ")" << std::endl;
}
}*/
return std::count_if(points.begin(), points.end(),
[this](const Point<MonkeyMetric>& point)
{return point.radius() <= this->m_bounds;} );
}
// Key function - this is the function that solves the monkey puzzle for one quadrant.
//
//This function simply creates a grid quadrant (0, d_max) by (0, d_max)
// iterates over all points in this quadrant, incrementing a counter if the maximum
// radial distance is not exceeded and at least one parent tree node is accessible.
unsigned get_accessible_quad_count(std::function<bool(const Point<MonkeyMetric>&)> constraints, bool
display = false)
{
unsigned count = 0;
for (unsigned level = 1; level <= 2*m_dmax; ++level) //loop over levels
{
std::vector<Point<MonkeyMetric>> current_level;
//current_level.reserve(level+1);
unsigned i = 0;
for (unsigned y = std::max(level,m_dmax)-m_dmax; y <= std::min(level, m_dmax); ++y) //loop over
nodes, left to right
{
current_level.push_back( Point<MonkeyMetric>(level-y, y) ); //assign point to node
current_level[i].m_is_accessible = constraints(current_level[i]);//Apply constraints
count += (current_level[i].m_is_accessible ? 1 : 0); //Update quadrant count
++i;
}
m_parent_level = std::move(current_level);
}
return count+1; //include point at origin
}
//This function simply creates a grid quadrant (0, d_max) by (0, d_max)
// iterates over all points in this quadrant, incrementing a counter if the maximum
// radial distance is not exceeded.
unsigned get_radial_count(bool display = false)
{
auto constraints = [this](const Point<MonkeyMetric>& point){ return (point.radius() <= this->
m_bounds); };
return get_accessible_quad_count(constraints);
}
//This function converts from quadrant count to full count over all four quadrants
unsigned get_total_from_quad_count( unsigned quad_count )
{
// Multiplying quad by 4 gives overcounting of the X and Y axis points
//so subtract 4*(d_max+1), then need to add origin point
return 4 * quad_count - 4 * (m_dmax + 1) + 1;
}
//This function simply creates a grid quadrant (0, d_max) by (0, d_max)
// iterates over all points in this quadrant, incrementing a counter if the maximum
4. 4C:my_docsvirtual_machinesvmware_playershared_foldergeneral3_mathematical_challenge_code.cpp
// radial distance is not exceeded.
unsigned get_full_constraint_count(bool display = false)
{
auto constraints = [this](const Point<MonkeyMetric>& point)
{
int level = point.m_x + point.m_y;
int index = point.m_y - (level <= static_cast<int>(m_dmax) ? 0 : (level-m_dmax));
unsigned left_parent = std::max(0, index - 1);
unsigned right_parent = std::min(index, static_cast<int>(this->m_parent_level.size()) - 1);
return (point.radius() <= this->m_bounds &&
(this->m_parent_level[left_parent].m_is_accessible ||
this->m_parent_level[right_parent].m_is_accessible));
};
return get_total_from_quad_count(get_accessible_quad_count(constraints));
}
//This function simply creates a grid quadrant (0, d_max) by (0, d_max)
// iterates over all points in this quadrant, incrementing a counter to give total
// point count
unsigned get_no_constraint_count(bool display = false)
{
auto constraints = [this](const Point<MonkeyMetric>& point)
{
return true;
};
return get_total_from_quad_count(get_accessible_quad_count(constraints));
}
//This function displays the grid of points for a given bounds.
// "." are accessible points
// "X" are inaccessible points
// "-" are points that lie within bounds but are inaccessible because
// the monkey cannot find a path to them
void display(void)
{
//Get the fully constrained points
std::set<Point<MonkeyMetric>> accessible_points;
accessible_points.insert(Point<MonkeyMetric>(0, 0));
std::set<Point<MonkeyMetric>> partially_constrained_points;
auto constraints = [this, &accessible_points, &partially_constrained_points](const Point
<MonkeyMetric>& point)
{
int level = point.m_x + point.m_y;
int index = point.m_y - (level <= static_cast<int>(m_dmax) ? 0 : (level - m_dmax));
unsigned left_parent = std::max(0, index - 1);
unsigned right_parent = std::min(index, static_cast<int>(this->m_parent_level.size()) - 1);
bool is_accessible = (point.radius() <= this->m_bounds &&
(this->m_parent_level[left_parent].m_is_accessible ||
this->m_parent_level[right_parent].m_is_accessible));
if( is_accessible) accessible_points.insert(point);
bool is_partial = (point.radius() <= this->m_bounds &&
!(this->m_parent_level[left_parent].m_is_accessible ||
this->m_parent_level[right_parent].m_is_accessible));
if (is_accessible) accessible_points.insert(point);
if( is_partial )partially_constrained_points.insert(point);
return is_accessible;
};
get_accessible_quad_count(constraints);
for (int x = -static_cast<int>(m_dmax); x <= static_cast<int>(m_dmax); ++x)
{
std::cout << std::endl;
for (int y = -static_cast<int>(m_dmax); y <= static_cast<int>(m_dmax); ++y)
{
//Convert to quadrant coord by simply taking |x|, |y|
std::string s;
auto f = accessible_points.find(
Point<MonkeyMetric>(std::abs(x), std::abs(y)));
5. 5C:my_docsvirtual_machinesvmware_playershared_foldergeneral3_mathematical_challenge_code.cpp
s = (f != accessible_points.end() ? "." : "X");
f = partially_constrained_points.find(
Point<MonkeyMetric>(std::abs(x), std::abs(y)));
if (f != partially_constrained_points.end()) s = "+";
std::cout << s;
}
}
}
private:
unsigned m_bounds;
unsigned m_dmax;
std::vector<Point<MonkeyMetric>> m_parent_level;
};
//=======================================
//Very simple and non-exhaustive test harness
//======================================
struct TestSuite
{
//Call from main()
void run(void)
{
//Begin with the solution to the puzzle
std::cout << "==============================================================" << std::endl;
std::cout << "Calculating result please wait ..." << std::endl;
std::cout << std::endl << "The answer to the riddle is: " << SolveMonkeyPuzzle(19).
get_full_constraint_count() << std::endl;
std::cout << "==============================================================" << std::endl;
//Now run tests
std::cout << "==============================================================" << std::endl;
std::cout << std::endl << "Executing tests" << std::endl;
std::cout << "==============================================================" << std::endl;
//Run global test allowing visual inspection of accessible points found by algorithm
unsigned bounds = 10;
std::cout << std::endl << "Global test of code: Accessibility map for n=: " << bounds <<
". 'X'=inaccessible, '+'=within bounds, but no path connecting with origin, '.'=accessible
." << std::endl;
SolveMonkeyPuzzle(bounds).display();
std::cout << std::endl << std::endl << "Hit any key except Q to continue with tests. Hit Q to quit
and keep results in console" << std::endl;
char c;
std::cin >> c;
if (c == 'Q')
{
std::cout << "Display is paused. Hit any key to quit application";
std::cin >> c;
return;
}
//Pre-calculated radius values
std::pair<int, unsigned> radius[] =
{
std::make_pair(1, 1),
std::make_pair(-2, 2),
std::make_pair(3, 3),
std::make_pair(-4, 4),
std::make_pair(5, 5),
std::make_pair(-6, 6),
std::make_pair(7, 7),
std::make_pair(-8, 8),
std::make_pair(9, 9),
std::make_pair(-10, 1),
std::make_pair(11, 2),
std::make_pair(-12, 3),
std::make_pair(13, 4),
std::make_pair(-14, 5),
std::make_pair(15, 6),
std::make_pair(-16, 7),
std::make_pair(17, 8),
std::make_pair(-18, 9),