def mpf_matrix_fadd(A, B): """ Given a m x n matrix A and m x n matrix B either in numpy.matrix or mpmath.matrix format, this function computes the sum C = A + B exactly. The output matrix C is always given in the MPMATH format. Parameters ---------- A - m x n matrix B - m x n matrix Returns ------- C - m x n matrix """ if isinstance(A, numpy.matrix): try: A = python2mpf_matrix(A) except ValueError as e: raise ValueError('Cannot compute exact sum of two matrices. %s' % e) else: if not isinstance(A, mpmath.matrix): raise ValueError('Cannot compute exact sum of two matrices: unexpected input type, excpected numpy.matrix or mpmath.matrix but got %s') %type(A) if isinstance(B, numpy.matrix): try: B = python2mpf_matrix(B) except ValueError as e: raise ValueError('Cannot compute exact sum of two matrices. %s' % e) else: if not isinstance(B, mpmath.matrix): raise ValueError('Cannot compute exact sum of two matrices: unexpected input type, excpected numpy.matrix or mpmath.matrix but got %s') % type(B) #here both A and B are mpmath matrices #we consider that A and B are MPF matrices if their first elements are of type mpf, let's test it if not isinstance(A[0,0], mpmath.mpf) or not isinstance(B[0,0], mpmath.mpf): raise ValueError('Cannot compute exact product of two matrices: cannot sum complex matrices.') #test sizes if A.rows != B.rows or A.cols != B.cols: raise ValueError('Cannot compute exact sum of two matrices: incorrect sizes.') m = A.rows n = A.cols C = mp.zeros(m, n) for i in range(0, m): for j in range(0, n): C[i,j] = mpmath.fadd(A[i,j], B[i,j], exact=True) if mpmath.isnan(C[i,j]) or mpmath.isinf(C[i,j]): print('WARNING: in matrix sum an abnormal number (NaN/Inf) occured: %f' % C[i,j]) return C
def __init__(self, b, a): """ define a discrete transfer function with multiple precision coefficients Parameters ---------- b - deg_b x 1 matrix of filter coefficients a - deg_a x 1 matrix of filter coefficients Returns ------- """ if not isinstance(b, mpmath.matrix) or not isinstance(a, mpmath.matrix): if isinstance(b, numpy.matrix) and isinstance(a, numpy.matrix): b = python2mpf_matrix(b) a = python2mpf_matrix(a) else: raise ValueError('Cannot create a dTFmp object: expected mpmath.matrix or numpy.matrix arguments but instead got %s and %s' % (type(b), type(a))) # check if user gave transposed matrices if b.cols > 1 and b.rows == 1: b = b.transpose() if a.cols > 1 and a.rows == 1: a = a.transpose() if a.cols != 1 or b.cols != 1: # or b.rows != a.rows : raise ValueError('Cannot create a dTFmp pbject: incorrect sizes') n = a.rows if a[0, 0] != mpmath.mp.one: for i in range(0, n): # division cannot be performed exactly but we do it with doubled precision a[i, 0] = mpmath.fdiv(a[i, 0], a[0, 0], prec=a[i, 0]._mpf_[3] * 2) b[i, 0] = mpmath.fdiv(b[i, 0], b[0, 0], prec=b[i, 0]._mpf_[3] * 2) self._order = n - 1 self._num = b self._den = a # cached sollya numerator and denominator self._sollya = None
def mpf_matrix_lt_inverse(L): """ For a lower-triangular n x n real matrix L with 1s on the main diagonal this function computes its inverse X exactly such that L * X = I Matrix L must be in the numpy.matrix of mpmath.matrix formats. The function returns X as n x n real a mpmath.matrix Parameters ---------- L - n x n lower-triangular matrix Returns ------- X - n x n matrix """ if isinstance(L, numpy.matrix): try: L = python2mpf_matrix(L) except ValueError as e: raise ValueError('Cannot compute exact difference of two matrices. %s') % e else: if not isinstance(L, mpmath.matrix): raise ValueError('Cannot compute exact difference of two matrices: unexpected input type, excpected numpy.matrix or mpmath.matrix but got %s') % type(L) #checking the size if L.rows != L.cols: raise ValueError('Cannot compute inverse: matrix must be square but istead is %s x %s' % L.rows, L.cols) else: n = L.rows #checking if the matrix is indeed lower-triangular with 1s on the main diagonal for i in range(0,n): if L[i,i] != mpmath.mp.one: raise ValueError('Cannot compute inverse: matrix must have 1s on the main diagonal.') for j in range(i+1, n): if L[i,j] != mpmath.mp.zero: raise ValueError('Cannot compute inverse: matrix must be lower triangular.') X = mp.zeros(n, n) for i in range(0,n): X[:, i] = my_forward_subst(L, i) return X
def test_computeMSBSIF(nSimulations=1000): sollya.settings.display = sollya.binary nu = 1 ny = 1 nx = 5 F = random_Filter(nx, ny, nu, seed=5) #F = Butter(5, 1.2) #SS = LWDF.makeRealization(F) SS = State_Space.makeRealization(F) #a hardcoded example #A = np.matrix([[-0.1721, 0.004845, 0.2187],[0.004845, -0.08567, -0.1096], [0.2187, -0.1096, -0.4978]]) #B = np.matrix([[1.533], [0], [0]]) #C = np.matrix([-0.2256, 1.117, -1.089]) #D = np.matrix([0.03256]) #F = Filter(A=A,B=B,C=C,D=D) #SS = State_Space.makeRealization(F) u_bar = np.bmat([np.ones([1, nu])]) l_y_out = -15 #msb_u = np.bmat([np.zeros([1, SS.q])]) #lsb_u = -15 * np.bmat([np.ones([1, SS.q])]) msb_u = 0 lsb_u = -15 msb = SS._compute_MSB(u_bar) lsb, error_budget_y = SS._compute_LSB(l_y_out) Y, N = mpf_get_representation(mpmath.mpf(error_budget_y)) error_budget_y = sollya.SollyaObject(Y) * 2**sollya.SollyaObject(N) lsb_t = [lsb[0, i] for i in range(0, SS.l)] lsb_x = [lsb[0, i] for i in range(SS.l, SS.l + SS.n)] lsb_y = [lsb[0, i] for i in range(SS.l + SS.n, SS.l + SS.n + SS.p)] msb_ext = SS.compute_MSB_allvar_extended(u_bar, lsb_t, lsb_x, lsb_y) if (msb != msb_ext).any(): print( 'MSB computed with taking into account the propagation of the error due to the format (msb, lsb) differs from the initial format. Changing MSBs.\n' ) print('new MSBs:') msb = msb_ext print(msb) msb_t = [msb[0, i] for i in range(0, SS.l)] msb_x = [msb[0, i] for i in range(SS.l, SS.l + SS.n)] msb_y = [msb[0, i] for i in range(SS.l + SS.n, SS.l + SS.n + SS.p)] fileID = './SIF-' + time.strftime("%d%m%Y-%H%M%S") filename = fileID + '.txt' with open(filename, 'a') as f_handle: f_handle.write('%d\n%d\n%d\n%d\n' % (SS.q, SS.l, SS.n, SS.p)) #for i in range(0, SS.q): f_handle.write('%d %d\n' % (msb_u, lsb_u)) for i in range(0, SS.l): f_handle.write('%d %d\n' % (msb_t[i], lsb_t[i])) for i in range(0, SS.n): f_handle.write('%d %d\n' % (msb_x[i], lsb_x[i])) for i in range(0, SS.p): f_handle.write('%d %d %s\n' % (msb_y[i], l_y_out, str(error_budget_y).replace( " ", "").replace("\n", ""))) #f_handle.write('%s\n' % str(error_budget_y)) #write_matrix_hex(f_handle, SS.Z, ' ') Z_sollya, Zrows, Zcols = mpf_matrix_to_sollya(python2mpf_matrix(SS.Z)) for i in range(0, Zrows): for j in range(0, Zcols): f_handle.write('%s' % str(Z_sollya[i + j * Zcols]).replace( " ", "").replace("\n", "")) f_handle.write(' ') f_handle.write('\n') f_handle.close() print('Filter: \n') print(SS) print('y_out was initially set to: %d\n' % l_y_out) print('LSBs:\n') print(lsb) print('MSBs:\n') print(msb) u = np.random.rand(1, nSimulations) # quantize the simulations to the format lsb_u bits u_sollya = mpf_matrix_to_sollya( mpmath.matrix([ mpmath.nint(mp.mpf(u[0, i]) * 2**-lsb_u) / 2**-lsb_u for i in range(0, nSimulations) ]))[0] u_quantized = sollya_matrix_to_numpy(u_sollya, 1, nSimulations) # perform simulations either in exact or rounded y_simulated_sollya_exact = SS.to_dSSexact().simulate_rounded(u_quantized, prec=53) y_simulated_sollya = mpf_matrix_to_sollya(SS.to_dSSexact().simulate( u_quantized, exact=True))[0] filename = fileID + 'simulation' + '.txt' with open(filename, 'a') as f_handle: f_handle.write('%d\n' % nSimulations) for i in range(0, nSimulations): #for j in range (0, nu): f_handle.write('%s' % str(u_sollya[i]).replace(" ", "").replace("\n", "")) f_handle.write('\n') #for j in range(0,ny): f_handle.write( '%s ' % str(y_simulated_sollya[i]).replace(" ", "").replace("\n", "")) f_handle.write('\n') #f_handle.write(str(y_simulated_exact_sollya[i]) + ' ') #f_handle.write('\n') f_handle.close() return True
def simulate(self, u, exact=True, x0=None): """ Given a vector of inputs u this function simulates the output of the dSS system on these inputs. If the flag exact is set to True (default) then the simulation is performed exactly. Otherwise, on each iteration the SoPs are computed exactly and then the state variables are rounded to double precision. Parameters ---------- u - vector of inputs in the format numpy.matrix or mpmath.matrix of size q x T x0 - vector of inital states, if specified must be of size n x 1 exact - a flag wether to perform simulations in exact (by default) or to perform Returns ------- y - p x T matrix of outputs """ if not isinstance(u, mpmath.matrix): if isinstance(u, numpy.matrix): u = python2mpf_matrix(u) else: raise ValueError('Cannot perform simulation: u must be either mpmath.matrix or numpy.matrix') if u.rows != self._q: raise ValueError('Cannot perform somulation: u is of incorrect size') xk = mpmath.mp.zeros(self._n, 1) if x0: if not isinstance(x0, mpmath.matrix): if isinstance(x0, numpy.matrix): xk = python2mpf_matrix(x0) else: raise ValueError('Cannot perform simulation: initial state specified in incorrect format') if xk.rows != self._n: raise ValueError('Cannot perform simulation: initial state is of incorrect size') T = u.cols yk = mpmath.mp.zeros(self._p, T) if exact: for i in range(0, T): xkp1 = mpf_matrix_fmul(self._A, xk) xkp1 = mpf_matrix_fadd(xkp1, mpf_matrix_fmul(self._B, u[:, i])) yk[:, i] = mpf_matrix_fmul(self._C, xk) yk[:, i] = mpf_matrix_fadd(yk[:, i], mpf_matrix_fmul(self._D, u[:, i])) xk = xkp1 else: for i in range(0, T): xkp1 = mpf_matrix_fmul(self._A, xk) xkp1 = mpf_matrix_fadd(xkp1, mpf_matrix_fmul(self._B, u[:, i])) yk[:, i] = mpf_matrix_fmul(self._C, xk) yk[:, i] = mpf_matrix_fadd(yk[:, i], mpf_matrix_fmul(self._D, u[:, i])) for i in range(0, xk.rows): xk[i, 0] = mpmath.fadd(xkp1[i, 0], mpmath.mp.zero, prec=64, rounding='n') return yk
def __init__(self, A, B, C, D): """ The dSSmp class describes a discrete state space realization with coefficients in multiple precision A state space system :math:`(A,B,C,D)` is defined by .. math:: \left\lbrace \begin{aligned} x(k+1) &= Ax(k) + Bu(k) \\ y(k) &= Cx(k) + Du(k) \end{aligned}\right. with :math:`A \in \mathbb{R}^{n \times n}, B \in \mathbb{R}^{n \times q}, C \in \mathbb{R}^{p \times n} \text{ and } D \in \mathbb{R}^{p \times q}`. **Dimensions of the state space :** .. math:: :align: left n,p,q \in \mathbb{N} == ================== n number of states p number of outputs q number of inputs == ================== Parameters ---------- A B C D Returns ------- """ if not isinstance(A, mpmath.matrix): if isinstance(A, numpy.matrix): A = python2mpf_matrix(A) else: raise ValueError('Cannot create dSSmp object: expected mpmath.matrix of numpy.matrix') if not isinstance(B, mpmath.matrix): if isinstance(B, numpy.matrix): B = python2mpf_matrix(B) else: raise ValueError('Cannot create dSSmp object: expected mpmath.matrix of numpy.matri') if not isinstance(C, mpmath.matrix): if isinstance(C, numpy.matrix): C = python2mpf_matrix(C) else: raise ValueError('Cannot create dSSmp object: expected mpmath.matrix of numpy.matrix') if not isinstance(D, mpmath.matrix): if isinstance(D, numpy.matrix): D = python2mpf_matrix(D) else: raise ValueError('Cannot create dSSmp object: expected mpmath.matrix of numpy.matrix') # checking sizes # n = A.rows if A.rows != A.cols: raise ValueError('Cannot create dSSmp object: incorrect sizes') else: self._n = A.rows if B.rows != self._n: raise ValueError('Cannot create dSSmp object: incorrect sizes') else: self._q = B.cols if C.cols != self._n: raise ValueError('Cannot create dSSmp object: incorrect sizes') else: self._p = C.rows if D.rows != self._p or D.cols != self._q: raise ValueError('Cannot create dSSmp object: incorrect sizes') self._A = A self._B = B self._C = C self._D = D