-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMPI_Map.cpp
166 lines (129 loc) · 5.22 KB
/
MPI_Map.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//
// MPI_Map.cpp
//
#include "MPI_Map.h"
#include "MPI_Point2D.h"
#include <cassert>
void MPI_Map::appendBreakpoint( MPI_Point2D const& point )
{
// append the next breapoint to the breakpoint list.
// the x value of the point *must* be strictly greater than the x value of
// the previous breakpoint.
// assert that they're being appended in order
assert( breakpoints_.size() == 0 || getLastBreakpoint().getX() < point.getX() );
// append the breakpoint
breakpoints_.push_back( point );
}
bool MPI_Map::inRange( float x ) const
{
// return true if x is in the range of the function, ie.
// [firstbreakpoint.getX(), lastbreakpoint.getX()]
// this method is used to check when it's valid to call
// getBreakpointAtOrBefore() or evaluate()
if ( breakpoints_.size() == 0 )
return false;
else
return getFirstBreakpoint().getX() <= x && x <= getLastBreakpoint().getX();
}
bool MPI_Map::inRangeOpenEnd( float x ) const
{
// return true if x is in the range of the function and before the last
// breakpoint, ie.
// [firstbreakpoint.getX(), lastbreakpoint.getX()) <- nb: open end
// this method is used to check when it's valid to call
// getBreakpointAfter()
if ( breakpoints_.size() == 0 )
return false;
else
return getFirstBreakpoint().getX() <= x && x < getLastBreakpoint().getX();
}
bool MPI_Map::isEmpty( void ) const
{
return breakpoints_.size() == 0;
}
float MPI_Map::evaluate( float x ) const
{
// evaluate the map as a piecewise linear function.
// assumes inRange(x) is true, ie, that x is on
// [firstbreakpoint.getX(), lastbreakpoint.getX()]
// check if x is in line with the last breakpoint; if so, return the
// appropriate y value without computing. the getBreakpointAfter() method
// won't accept an x value in line with the last breakpoint.
if ( x == getLastBreakpoint().getX() )
return getLastBreakpoint().getY();
// get the breakpoints before and after
MPI_Point2D const& before = getBreakpointAtOrBefore( x );
MPI_Point2D const& after = getBreakpointAfter( x );
// linearly interpolate. this expression comes from a simple algebraic
// manipuation of the interpolation function.
return ((after.getX()-x)*before.getY() + (x-before.getX())*after.getY()) /
(after.getX() - before.getX());
}
MPI_Point2D const& MPI_Map::getBreakpointAtOrBefore( float x ) const
{
// return the closest breakpoint whose x value is equal to or less than the
// argument (x). Assumes that x is on
// [firstbreakpoint.getX(), lastbreakpoint.getX()]
// ie, that inRange(x) is true
// we find the breakpoint that comes strictly after x, decrement it,
// and then return its value. the reason we do it this way is because of
// how lower_bound and upper_bound work. lower_bound() returns the first
// item at or after the argument; upper_bound() returns the first item
// after the argument. Since we want to access the breakpoints on either
// side of the argument, lower_bound() wouldn't work since we wouldn't know
// without checking whether we should decrement it or not. We know that
// we'll always have to when working with upper_bound().
std::list<MPI_Point2D>::const_iterator breakpoint;
// find the closest breakpoint that comes strictly after x
breakpoint = upper_bound( breakpoints_.begin(), breakpoints_.end(),
MPI_Point2D( x, 0.0 ), BreakpointBefore() );
// return the one just before the one we found
--breakpoint;
return *breakpoint;
}
MPI_Point2D const& MPI_Map::getBreakpointAfter( float x ) const
{
// return the closest breakpoint whose x value is greater than the argument
// (x). Assumes that x is on
// [firstbreakpoint.getX(), lastbreakpoint.getX()) <-- open at right
// ie, that inRangeOpenEnd(x) is true
// (NB: x cannot be in line with the last breakpoint. Must check for this
// case before calling this method.)
// see notes in getBreakpointAtOrBefore() for the reasoning behind how
// these methods work.
std::list<MPI_Point2D>::const_iterator breakpoint;
// find the closest breakpoint that comes strictly after x
breakpoint = upper_bound( breakpoints_.begin(), breakpoints_.end(),
MPI_Point2D( x, 0.0 ), BreakpointBefore() );
// return its value
return *breakpoint;
}
MPI_Point2D const& MPI_Map::getFirstBreakpoint( void ) const
{
// this method assumes breakpoints_ is nonempty.
return breakpoints_.front();
}
MPI_Point2D const& MPI_Map::getLastBreakpoint( void ) const
{
// this method assumes breakpoints_ is nonempty.
return breakpoints_.back();
}
void MPI_Map::print( std::ostream &os ) const
{
std::list<MPI_Point2D>::const_iterator currentbp;
for ( currentbp = breakpoints_.begin(); currentbp != breakpoints_.end();
++currentbp )
os << *currentbp << ", ";
os << "done";
}
bool MPI_Map::BreakpointBefore::operator()( MPI_Point2D const& a, MPI_Point2D const& b ) const
{
// return true if a comes strictly before b in the domain
return a.getX() < b.getX();
}
std::ostream &operator<<( std::ostream &os, MPI_Map const &map )
{
map.print(os);
return os;
}
// vim:sw=4:et:cindent: