# -*- coding: utf-8 -*-
#
# This file is subject to the terms and conditions defined in
# file 'LICENSE', which is part of this source code package.
#
import numpy as np
import bisect
[docs]def BinarySearch(orderedList, item):
"""
Inspects the sorted list "ordered_list" and returns:
- 0 if item <= orderedList[0]
- the rank of the largest element smaller or equal than item otherwise
Parameters
----------
ordered_list: list or one-dimensional np.ndarray
the data sorted in increasing order from which the previous rank is\
searched
item : float or int
the item for which the previous rank is searched
Returns
-------
int
0 or the rank of the largest element smaller or equal than item in\
"orderedList"
"""
return max(bisect.bisect_right(orderedList, item) - 1, 0)
[docs]def BinarySearchVectorized(orderedList, items):
"""
BinarySearch for more than one call (items is now a list or one-dimensional np.ndarray)
"""
return np.fromiter(map(lambda item: BinarySearch(orderedList, item), items), dtype = int)
[docs]def PieceWiseLinearInterpolation(item, itemIndices, vectors, tolerance = 1e-4):
"""
Computes a item interpolation for temporal vectors defined either by
itemIndices and vectors at these indices
Parameters
----------
item : float
the input item at which the interpolation is required
itemIndices : np.ndarray
the items where the available data is defined, of size
(numberOfTimeIndices)
vectors : np.ndarray or dict
the available data, of size (numberOfVectors, numberOfDofs)
tolerance : float
tolerance for deciding when using the closest timestep value instead of carrying out the linear interpolation
Returns
-------
np.ndarray
interpolated vector, of size (numberOfDofs)
"""
if item <= itemIndices[0]:
return vectors[0]
if item >= itemIndices[-1]:
return vectors[-1]
prev = BinarySearch(itemIndices, item)
coef = (item - itemIndices[prev]) / (itemIndices[prev+1] - itemIndices[prev])
if 0.5 - abs(coef - 0.5) < tolerance:
coef = round(coef)
return (
coef * vectors[prev+1]
+ (1 - coef) * vectors[prev]
)
[docs]def PieceWiseLinearInterpolationWithMap(item, itemIndices, vectors, vectorsMap, tolerance = 1e-4):
"""
Computes a item interpolation for temporal vectors defined either by
itemIndices, some tags at these item indices (vectorsMap), and vectors at those tags.
Parameters
----------
item : float
the input item at which the interpolation is required
itemIndices : np.ndarray
the items where the available data is defined, of size
(numberOfTimeIndices)
vectors : np.ndarray or dict
the available data, of size (numberOfVectors, numberOfDofs)
vectorsMap : list
list containing the mapping from the numberOfTimeIndices items indices to the numberOfVectors vectors, of size (numberOfTimeIndices,). Default is None, in which case numberOfVectors = numberOfTimeIndices.
tolerance : float
tolerance for deciding when using the closest timestep value instead of carrying out the linear interpolation
Returns
-------
np.ndarray
interpolated vector, of size (numberOfDofs)
"""
if item <= itemIndices[0]:
return vectors[vectorsMap[0]]
if item >= itemIndices[-1]:
return vectors[vectorsMap[-1]]
prev = BinarySearch(itemIndices, item)
coef = (item - itemIndices[prev]) / (itemIndices[prev+1] - itemIndices[prev])
if 0.5 - abs(coef - 0.5) < tolerance:
coef = round(coef)
return (
coef * vectors[vectorsMap[prev+1]]
+ (1 - coef) * vectors[vectorsMap[prev]]
)
[docs]def PieceWiseLinearInterpolationVectorized(items, itemIndices, vectors):
"""
PieceWiseLinearInterpolation for more than one call (items is now a list or one-dimensional np.ndarray)
"""
return [PieceWiseLinearInterpolation(item, itemIndices, vectors) for item in items]
#return np.fromiter(map(lambda item: PieceWiseLinearInterpolation(item, itemIndices, vectors), items), dtype = type(vectors[0]))
[docs]def PieceWiseLinearInterpolationVectorizedWithMap(items, itemIndices, vectors, vectorsMap):
"""
PieceWiseLinearInterpolation for more than one call (items is now a list or one-dimensional np.ndarray)
"""
return [PieceWiseLinearInterpolationWithMap(item, itemIndices, vectors, vectorsMap) for item in items]
#return np.fromiter(map(lambda item: PieceWiseLinearInterpolationWithMap(item, itemIndices, vectors, vectorsMap), items), dtype = np.float)
[docs]def CheckIntegrity(GUI=False):
timeIndices = np.array([0.0, 1.0, 2.5])
vectors = np.array([np.ones(5), 2.0 * np.ones(5), 3.0 * np.ones(5)])
vectorsDic = {}
vectorsDic["vec1"] = np.ones(5)
vectorsDic["vec2"] = 2.0 * np.ones(5)
vectorsMap = ["vec1", "vec2", "vec1"]
res = PieceWiseLinearInterpolation(-1.0, timeIndices, vectors)
np.testing.assert_almost_equal(res, [1., 1., 1., 1., 1.])
res = PieceWiseLinearInterpolationWithMap(3.0, timeIndices, vectorsDic, vectorsMap)
np.testing.assert_almost_equal(res, [1., 1., 1., 1., 1.])
res = PieceWiseLinearInterpolation(1.0, timeIndices, vectors)
np.testing.assert_almost_equal(res, [2., 2., 2., 2., 2.])
res = PieceWiseLinearInterpolationWithMap(1.0, timeIndices, vectorsDic, vectorsMap)
np.testing.assert_almost_equal(res, [2., 2., 2., 2., 2.])
res = PieceWiseLinearInterpolation(0.4, timeIndices, vectors)
np.testing.assert_almost_equal(res, [1.4, 1.4, 1.4, 1.4, 1.4])
res = PieceWiseLinearInterpolation(1.4, timeIndices, vectors)
np.testing.assert_almost_equal(res, [6.8/3, 6.8/3, 6.8/3, 6.8/3, 6.8/3])
res = PieceWiseLinearInterpolationWithMap(0.6, timeIndices, vectorsDic, vectorsMap)
np.testing.assert_almost_equal(res, [1.6, 1.6, 1.6, 1.6, 1.6])
res = PieceWiseLinearInterpolationVectorizedWithMap(np.array([-0.1, 2.0, 3.0]), timeIndices, vectorsDic, vectorsMap)
np.testing.assert_almost_equal(res, [np.array([1., 1., 1., 1., 1.]), np.array([1.33333333, 1.33333333, 1.33333333, 1.33333333, 1.33333333]), np.array([1., 1., 1., 1., 1.])])
timeIndices = np.array([0., 100., 200., 300., 400., 500., 600., 700.,\
800., 900., 1000., 2000.])
coefficients = np.array([2000000., 2200000., 2400000., 2000000., 2400000.,\
3000000., 2500000., 2400000., 2100000., 2800000.,\
4000000., 3000000.])
vals = np.array([-10., 0., 100., 150., 200., 300., 400., 500., 600., 700.,\
800., 900., 1000., 3000., 701.4752695491923])
res = np.array([2000000., 2000000., 2200000., 2300000., 2400000., 2000000.,\
2400000., 3000000., 2500000., 2400000., 2100000., 2800000.,\
4000000., 3000000., 2395574.19135242])
for i in range(vals.shape[0]):
assert (PieceWiseLinearInterpolation(vals[i], timeIndices, coefficients) - res[i])/res[i] < 1.e-10
res = PieceWiseLinearInterpolationVectorized(np.array(vals), timeIndices, coefficients)
np.testing.assert_almost_equal(res, [2000000.0, 2000000.0, 2200000.0, 2300000.0, 2400000.0, 2000000.0, 2400000.0, 3000000.0, 2500000.0, 2400000.0, 2100000.0, 2800000.0, 4000000.0, 3000000.0, 2395574.1913524233])
testlist = np.array([0.0, 1.0, 2.5, 10.])
valList = np.array([-1., 11., 0.6, 2.0, 2.6, 9.9, 1.0])
ref = np.array([0, 3, 0, 1, 2, 2, 1], dtype = int)
res = BinarySearchVectorized(testlist, valList)
for i, val in enumerate(valList):
assert BinarySearch(testlist, val) == ref[i]
assert res[i] == ref[i]
return "ok"
if __name__ == '__main__':
print(CheckIntegrity()) #pragma: no cover