# -*- coding: utf-8 -*-
"""
=========================================
DABI Miscellaneous
=========================================
Created on Wed Feb 27
@author: Daniele Bigoni (dabi@dtu.dk)
Collection of miscellaneous functions used in the DABISpectralToolbox
"""
__revision__ = filter(str.isdigit, "$Revision: 101 $")
__author__ = "Daniele Bigoni"
__copyright__ = """Copyright 2012, Daniele Bigoni"""
__credits__ = ["Daniele Bigoni"]
__maintainer__ = "Daniele Bigoni"
__email__ = "dabi@dtu.dk"
__status__ = "Production"
import numpy as np
[docs]def MultiIndex(d,N):
"""
MultiIndex(): generates the multi index ordering for the construction of multidimensional Generalized Vandermonde matrices
Syntax:
``IDX = MultiIndex(d,N)``
Input:
* ``d`` = (int) dimension of the simplex
* ``N`` = (int) the maximum value of the sum of the indeces
OUTPUT:
* ``IDX`` = (2d-array,int) array containing the ordered multi indeces
"""
from scipy.misc import comb
# Compute the size of the number of multi-index elements (Pascal's simplex)
NIDX = 0
for i in range(0,N+1):
NIDX = NIDX + comb( i+(d-1),d-1,True)
# Allocate memory
IDX = np.zeros((NIDX,d),dtype=int)
iIDX = 1 # index in the multi-index table on which the first n-th order is
for n in range(1,N+1):
IDX[iIDX,0] = n
# Start recursion
iIDX = __MultiIndexRec(IDX,d,iIDX+1,0)
return IDX
def __MultiIndexRec(IDX,d,m,i):
# Start splitting
mFirstSplit = m-1
mLastSplit = m-1
mNew = m
if (i+1 < d):
while (IDX[mLastSplit,i] > 1):
IDX[mNew,:i] = IDX[mLastSplit,:i]
IDX[mNew,i] = IDX[mLastSplit,i]-1
IDX[mNew,i+1] = IDX[mLastSplit,i+1]+1
mLastSplit = mNew
mNew = mNew + 1
# Call recursion on sub set
mNew = __MultiIndexRec(IDX,d,mNew,i+1)
# Move
IDX[mNew,:i] = IDX[mFirstSplit,:i]
IDX[mNew,i+1] = IDX[mFirstSplit,i]
mNew = mNew + 1
# Call recursion on sub set
mNew = __MultiIndexRec(IDX,d,mNew,i+1)
return mNew
[docs]def machineEpsilon(func=float):
"""
machineEpsilon(): returns the abolute machine precision for the type passed as argument
Syntax:
``eps = machineEpsilon([func=float])``
Input:
* ``func`` : (default=float) type
OUTPUT:
* ``eps`` : absolute machine precision
"""
machine_epsilon = func(1)
while func(1)+func(machine_epsilon) != func(1):
machine_epsilon_last = machine_epsilon
machine_epsilon = func(machine_epsilon) / func(2)
return machine_epsilon_last
[docs]def compare(x,y,tol):
"""
compare(): compares two values up to a certain tolerance
Syntax:
``n = compare(x,y,tol)``
Input:
* ``x``, ``y`` : (float) values to be compared
* ``tol`` : (float) tolerance to be used
OUTPUT:
* ``n`` : returns -1 if ``(x-y) < tol``, 1 if ``(x-y) > tol``, 0 otherwise
"""
for x_i,y_i in zip(x,y):
d = x_i-y_i
if (d < -tol):
return -1
elif (d > tol):
return 1
return 0
[docs]def almostEqual(x,y,tol):
"""
almostEqual(): check equality of two values up to a certain tolerance
Syntax:
``b = almostEqual(x,y,tol)``
Input:
* ``x``, ``y`` : (float) values to be compared
* ``tol`` : (float) tolerance to be used
OUTPUT:
* ``b`` : returns ``true`` if equal, ``false`` otherwise
"""
return (compare(x,y,tol)==0)
[docs]def almostEqualList(xArray,y,tol):
"""
almostEqualList(): check equality of a list of floats against a value up to certain tolerance
Syntax:
``b = almostEqualList(xArray,y,tol)``
Input:
* ``xArray``: (1d-array,float) values to be compared to ``y``
* ``y`` : (float) values to be compared to
* ``tol`` : (float) tolerance to be used
OUTPUT:
* ``b`` : (1d-array,bool) true if equal, false otherwise.
"""
if type(y) != np.ndarray and (np.dtype(y) == float and len(xArray.shape) == 1):
y = np.array([y])
xArray = xArray.reshape((len(xArray),1))
if xArray.shape[1] == len(y):
out = np.zeros(xArray.shape[0],dtype=bool)
for i in range(xArray.shape[0]):
out[i] = (almostEqual(xArray[i,:],y,tol))
return out
else:
print "Dimension error!"
return
[docs]def binary_search(X, val, lo, hi, tol, perm=None):
"""
binary_search(): search for the maximum X smaller than val
Syntax:
``idx = binary_search(X,val,lo,hi,tol,[perm=None])``
Input:
* ``X``: (2d-array,float) values ordered by row according to the compare function
* ``val`` : (1d-array,float) value to be compared to
* ``lo`` : (int) starting index
* ``hi`` : (int) ending index
* ``tol`` : (float) tolerance to be used
* ``perm``: (optional,1d-array,int) possible permutation to be used prior to the search.
OUTPUT:
* ``idx`` : (int) Index pointing to the maximum X smaller than val. If ``perm`` is provided, ``perm[idx]`` points to the maximum X smaller than val.
"""
if perm == None:
perm = np.arange(lo,hi)
while lo+1 < hi:
mid = (lo+hi)//2
midval = X[perm[mid],]
comp = compare(midval,val,tol)
if comp == -1:
lo = mid
elif comp == 1:
hi = mid
elif comp == 0:
return mid
return hi
[docs]def argsort_insertion(X,tol,start_idx=1,end_idx=None):
"""
argsort_insertion(): Implements the insertion sort with ``binary_search``. Returns permutation indices.
Syntax:
``perm = argsort_insertion(X,tol,[start_idx=1],[end_idx=None])``
Input:
* ``X``: (2d-array,float) values ordered by row according to the compare function
* ``tol`` : (float) tolerance to be used
* ``start_idx``: (int) starting index for the ordering
* ``end_idx`` : (int) ending index for the ordering
OUTPUT:
* ``perm`` : (1d-array,int) permutation indices
"""
if end_idx == None:
end_idx = X.shape[0]
if start_idx < 1:
start_idx = 1
perm = range(0,end_idx)
for i in range(start_idx,len(perm)):
val = perm[i]
# Binary search
idx = binary_search(X,X[val,],-1,i+1,tol,perm=perm) # idx contains the index in perm of the last X < val
perm[idx+1:i+1] = perm[idx:i]
perm[idx] = val
return perm
[docs]class ExpandingArray:
__DEFAULT_ALLOC_INIT_DIM = 10 # default initial dimension for all the axis is nothing is given by the user
__DEFAULT_MAX_INCREMENT = 10 # default value in order to limit the increment of memory allocation
__MAX_INCREMENT = [] # Max increment
__ALLOC_DIMS = [] # Dimensions of the allocated np.array
__DIMS = [] # Dimensions of the view with data on the allocated np.array (__DIMS <= __ALLOC_DIMS)
__ARRAY = [] # Allocated array
def __init__(self,initData,allocInitDim=None,dtype=np.float64,maxIncrement=None):
"""
Initialization of the Expanding Array.
:param initData: data
Syntax:
``EA = ExpandingArray(initData,[allocInitDim=None,[dtype=np.float64,[maxIncrement=None]]])``
Input:
* ``initData`` = (nd-array) InitialData with which to be initially filled. This must provide the number of dimensions of the array.
* ``allocInitDim`` = (optional,1d-array,int) Initial allocated dimension.
* ``dtype`` = (optional,dtype=np.float64) type for the data that will be contained in ``EA``
* ``maxIncrement`` = (int) upper limit for the allocation increment
Description:
"""
self.__DIMS = np.array(initData.shape)
self.__MAX_INCREMENT = maxIncrement
if self.__MAX_INCREMENT == None:
self.__MAX_INCREMENT = self.__DEFAULT_MAX_INCREMENT
''' Compute the allocation dimensions based on user's input '''
if allocInitDim == None:
allocInitDim = self.__DIMS.copy()
while np.any( allocInitDim < self.__DIMS ) or np.any(allocInitDim == 0):
for i in range(len(self.__DIMS)):
if allocInitDim[i] == 0:
allocInitDim[i] = self.__DEFAULT_ALLOC_INIT_DIM
if allocInitDim[i] < self.__DIMS[i]:
allocInitDim[i] += min(allocInitDim[i]/2, self.__MAX_INCREMENT)
''' Allocate memory '''
self.__ALLOC_DIMS = allocInitDim
self.__ARRAY = np.zeros(self.__ALLOC_DIMS,dtype=dtype)
''' Set initData '''
sliceIdxs = [slice(self.__DIMS[i]) for i in range(len(self.__DIMS))]
self.__ARRAY[sliceIdxs] = initData
[docs] def shape(self):
return tuple(self.__DIMS)
[docs] def getAllocArray(self):
return self.__ARRAY
[docs] def getDataArray(self):
'''
Get the view of the array with data
'''
sliceIdxs = [slice(self.__DIMS[i]) for i in range(len(self.__DIMS))]
return self.__ARRAY[sliceIdxs]
[docs] def concatenate(self,X,axis=0):
if axis > len(self.__DIMS):
print "Error: axis number exceed the number of dimensions"
return
''' Check dimensions for remaining axis '''
for i in range(len(self.__DIMS)):
if i != axis:
if X.shape[i] != self.shape()[i]:
print "Error: Dimensions of the input array are not consistent in the axis %d" % i
return
''' Check whether allocated memory is enough '''
needAlloc = False
while self.__ALLOC_DIMS[axis] < self.__DIMS[axis] + X.shape[axis]:
needAlloc = True
''' Increase the __ALLOC_DIMS '''
self.__ALLOC_DIMS[axis] += min(self.__ALLOC_DIMS[axis]/2,self.__MAX_INCREMENT)
''' Reallocate memory and copy old data '''
if needAlloc:
''' Allocate '''
newArray = np.zeros(self.__ALLOC_DIMS)
''' Copy '''
sliceIdxs = [slice(self.__DIMS[i]) for i in range(len(self.__DIMS))]
newArray[sliceIdxs] = self.__ARRAY[sliceIdxs]
self.__ARRAY = newArray
''' Concatenate new data '''
sliceIdxs = []
for i in range(len(self.__DIMS)):
if i != axis:
sliceIdxs.append(slice(self.__DIMS[i]))
else:
sliceIdxs.append(slice(self.__DIMS[i],self.__DIMS[i]+X.shape[i]))
self.__ARRAY[sliceIdxs] = X
self.__DIMS[axis] += X.shape[axis]
[docs] def trim(self,N,axis=0):
"""
Trim the axis dimension of N elements
"""
self.__DIMS[axis] = max(self.__DIMS[axis]-N,0)