Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F10547074
History.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Size
7 KB
Referenced Files
None
Subscribers
None
History.hpp
View Options
/*******************************************************************************
*
* File: History.hpp
*
* Contents: Definition of History Module.
*
* Copyright 2017
*
* Author: David Juhasz (david.juhasz@tuwien.ac.at)
*
******************************************************************************/
#ifndef ROSA_AGENT_HISTORY_HPP
#define ROSA_AGENT_HISTORY_HPP
#include
"rosa/agent/Module.h"
#include
"rosa/config/config.h"
#include
"rosa/support/debug.hpp"
#include
"rosa/support/type_helper.hpp"
#include
<array>
namespace
rosa
{
namespace
agent
{
// Retention policies defining what a History instance should do when the
// number of recorded entries reached its capacity.
enum
class
HistoryPolicy
{
SRWF
,
// Stop Recording When Full -- no new entry is recorded when full
FIFO
// First In First Out -- overwrite the earliest entry with a new one
};
// NOTE: Not thread-safe implementation, which should not be a problem as a
// Module instance is an internal component of an Agent, which is the basic
// unit of concurrency.
template
<
typename
T
,
size_t
N
,
HistoryPolicy
P
>
class
History
:
public
Module
,
private
std
::
array
<
T
,
N
+
1
>
{
// Bring into scope inherited functions that are used.
// INV: max_size() == N + 1 && N == max_size() - 1
using
std
::
array
<
T
,
N
+
1
>::
max_size
;
using
std
::
array
<
T
,
N
+
1
>::
operator
[];
// The indices of the first data element and the first empty slot in the
// circular buffer.
size_t
Data
,
Space
;
public
:
// Ctor. Initializes indices.
History
(
void
)
noexcept
:
Data
(
0
),
Space
(
0
)
{}
// Dtor.
~
History
(
void
)
=
default
;
// Tells the policy applied to the History.
static
constexpr
HistoryPolicy
policyOfHistory
(
void
)
noexcept
{
return
P
;
}
// Tells how many entries may be recorded by the History.
// NOTE: The number of entries that are actually recorded may be smaller.
static
constexpr
size_t
lengthOfHistory
(
void
)
noexcept
{
return
N
;
}
// Tells how many entries are currently recorded by the History.
// POST: 0 <= numberOfEntries() && numberOfEntries <= lengthOfHistory()
inline
size_t
numberOfEntries
(
void
)
const
noexcept
{
return
Data
<=
Space
?
Space
-
Data
:
max_size
()
-
Data
+
Space
;
}
// Tells if the History has not recorded any entries yet.
inline
bool
empty
(
void
)
const
noexcept
{
return
numberOfEntries
()
==
0
;
}
// Gives a constant lvalue reference to the I-th latest entry stored in the
// History.
// PRE: 0 <= I && I <= numberOfEntries()
const
T
&
entry
(
const
size_t
I
=
0
)
const
noexcept
{
ASSERT
(
0
<=
I
&&
I
<
numberOfEntries
());
// Boundary check.
// Position counted back from the last recorded entry.
typename
std
::
make_signed
<
const
size_t
>::
type
Pos
=
Space
-
(
1
+
I
);
// Actual index wrapped around to the end of the buffer if negative.
return
(
*
this
)[
Pos
>=
0
?
Pos
:
max_size
()
+
Pos
];
}
private
:
// Tells if the circular buffer is full.
inline
bool
full
(
void
)
const
noexcept
{
return
numberOfEntries
()
==
N
;
}
// Pushes a new entry into the circular buffer, removing the earliest entry
// if the buffer is full.
void
pushBack
(
const
T
&
V
)
noexcept
{
// Store value to the first empty slot and step Space index.
(
*
this
)[
Space
]
=
V
;
Space
=
(
Space
+
1
)
%
max_size
();
if
(
Data
==
Space
)
{
// Buffer was full, step Data index.
Data
=
(
Data
+
1
)
%
max_size
();
}
}
public
:
// Adds a new entry to the History and tells if the operation was successful.
// NOTE: Success of the operation depends on the actual policy.
bool
addEntry
(
const
T
&
V
)
noexcept
{
switch
(
P
)
{
default
:
ROSA_CRITICAL
(
"unkown HistoryPolicy"
);
case
HistoryPolicy
::
SRWF
:
if
(
full
())
{
return
false
;
}
// NOTE: Fall through to FIFO which unconditionally pushes the new entry.
case
HistoryPolicy
::
FIFO
:
// FIFO and SRWF not full.
pushBack
(
V
);
return
true
;
}
}
// Tells the trend set by the entries recorded by the History. The number of
// steps to go back in the History is given as argument.
// NOTE: The number of steps that can be made is limited by the number of
// entries recorded by the History.
// NOTE: The function is made a template only to be able to use enable_if.
// STATIC PRE: std::is_arithmetic<T>::value && std::is_signed<T>::value
// PRE: 0 <= D && D < N
template
<
typename
X
=
T
>
typename
std
::
enable_if
<
std
::
is_arithmetic
<
X
>::
value
&&
std
::
is_signed
<
X
>::
value
,
X
>::
type
trend
(
const
size_t
D
=
N
-
1
)
const
noexcept
{
STATIC_ASSERT
((
std
::
is_same
<
X
,
T
>::
value
),
"not default template arg"
);
ASSERT
(
0
<=
D
&&
D
<
N
);
// Boundary check.
if
(
numberOfEntries
()
<
2
||
D
<
1
)
{
// No entries for computing trend.
return
{};
// Zero element of T
}
else
{
// Here at least two entries.
// S is the number of steps that can be done.
const
size_t
S
=
std
::
min
(
numberOfEntries
()
-
1
,
D
);
size_t
I
=
S
;
// Compute trend with linear regression.
size_t
SumIndices
=
0
;
T
SumEntries
=
{};
T
SumSquareEntries
=
{};
T
SumProduct
=
{};
while
(
I
>
0
)
{
// NOTE: Indexing for the regression starts in the past.
const
size_t
Index
=
S
-
I
;
const
T
Entry
=
entry
(
--
I
);
SumIndices
+=
Index
;
SumEntries
+=
Entry
;
SumSquareEntries
+=
Entry
*
Entry
;
SumProduct
+=
Entry
*
Index
;
}
return
(
SumProduct
*
S
-
SumEntries
*
SumIndices
)
/
(
SumSquareEntries
*
S
-
SumEntries
*
SumEntries
);
}
}
// Tells the average absolute difference between consequtive entries recorded
// by the History. The number of steps to go back in the History is given as
// argument.
// NOTE: The number of steps that can be made is limited by the number of
// entries recorded by the History.
// NOTE: The function is made a template only to be able to use enable_if.
// STATIC PRE: std::is_arithmetic<T>::value
// PRE: 0 <= D && D < N
template
<
typename
X
=
T
>
typename
std
::
enable_if
<
std
::
is_arithmetic
<
X
>::
value
,
unsigned_t
<
X
>>::
type
averageAbsDiff
(
const
size_t
D
=
N
-
1
)
const
noexcept
{
STATIC_ASSERT
((
std
::
is_same
<
X
,
T
>::
value
),
"not default template arg"
);
ASSERT
(
0
<=
D
&&
D
<
N
);
// Boundary check.
if
(
numberOfEntries
()
<
2
||
D
<
1
)
{
// No difference to average.
return
{};
// Zero element of T
}
else
{
// Here at least two entries.
// S is the number of steps that can be done.
const
size_t
S
=
std
::
min
(
numberOfEntries
()
-
1
,
D
);
// Sum up differences as non-negative values only, hence using an
// unsigned variable for that.
unsigned_t
<
T
>
Diffs
=
{};
// Init to zero.
// Count down entry indices and sum up all the absolute differences.
size_t
I
=
S
;
T
Last
=
entry
(
I
);
while
(
I
>
0
)
{
T
Next
=
entry
(
--
I
);
Diffs
+=
Last
<
Next
?
Next
-
Last
:
Last
-
Next
;
Last
=
Next
;
}
// Return the average of the summed differences.
return
Diffs
/
S
;
}
}
};
// Convenience operator to add new entries to a History instance.
// NOTE: The result of the member function addEntry is ignored by the operator.
template
<
typename
T
,
size_t
N
,
HistoryPolicy
P
>
History
<
T
,
N
,
P
>
&
operator
<<
(
History
<
T
,
N
,
P
>
&
H
,
const
T
&
V
)
noexcept
{
H
.
addEntry
(
V
);
return
H
;
}
}
// End namespace agent
}
// End namespace rosa
#endif
// ROSA_AGENT_HISTORY_HPP
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sat, May 30, 11:41 PM (16 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
328043
Default Alt Text
History.hpp (7 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment