ulinalg.py

Created by asness

Created on February 09, 2019

6.64 KB

Matrices for the Python interpreter. An attempt to port https://github.com/jalawson/ulinalg


_B='//'
_A='**'
stypes=[bool,int]
ddtype=int
estypes=[]
flt_eps=1
class matrix(object):
  def __init__(A,data,cstride=0,rstride=0,dtype=None):
    F=rstride;E=dtype;D=cstride;B=data
    if D!=0:
      if D==1:A.n=F;A.m=int(len(B)/A.n)
      else:A.m=D;A.n=int(len(B)/A.m)
      A.cstride=D;A.rstride=F;A.data=B
    else:
      A.n=1
      if type(B)==int:A.m=1
      else:
        A.m=len(B)
        if type(B[0])==list:A.n=len(B[0])
      A.data=[B[C][G]for C in(range(A.m))for G in(range(A.n))];A.cstride=1;A.rstride=A.n
    if E is None:A.dtype=stypes[max([stypes.index(type(C))for C in(A.data)])]
    elif E in stypes:A.dtype=E
    else:raise TypeError('unsupported type',E)
    A.data=[A.dtype(C)for C in(A.data)]
  def __len__(A):return A.m
  def __eq__(A,other):
    B=other
    if A.shape==B.shape:D=all([A.data[C]==B.data[C]for C in(range(A.size()))]);return D and A.shape==B.shape
    else:raise ValueError('shapes not equal')
  def __ne__(A,other):return not __eq__(other)
  def __iter__(A):
    A.cur=0
    if A.m==1:A.cnt_lim=A.n
    else:A.cnt_lim=A.m
    return A
  def __next__(A):
    if A.cur>=A.cnt_lim:raise StopIteration
    A.cur=A.cur+1
    if A.m==1:return A.data[A.cur-1]
    else:return A[A.cur-1]
  def slice_to_offset(A,r0,r1,c0,c1):B=[A.data[C*A.rstride+D*A.cstride]for C in(range(r0,r1))for D in(range(c0,c1))];return matrix(B,cstride=1,rstride=c1-c0)
  def slice_indices(B,index,axis=0):
    C=axis;A=index
    if isinstance(A.start,type(None)):D=0
    else:D=min(int(A.start),B.shape[C])
    if isinstance(A.stop,type(None)):E=B.shape[C]
    else:E=min(int(A.stop),B.shape[C])
    return D,E
  def __getitem__(D,index):
    A=index
    if type(A)==tuple:
      if isinstance(A[0],int):B=A[0];E=B+1
      else:B,E=D.slice_indices(A[0],0)
      if isinstance(A[1],int):C=A[1];F=C+1
      else:C,F=D.slice_indices(A[1],1)
    elif type(A)==list:raise NotImplementedError('Fancy indexing')
    else:B=A;E=B+1;C=0;F=D.n
    G=D.slice_to_offset(B,E,C,F)
    if E==B+1 and F==C+1:return G.data[0]
    else:return G
  def __setitem__(C,index,val):
    B=index;A=val
    if type(B)!=tuple:raise NotImplementedError('Need to use the slice [1,:] format.')
    if isinstance(B[0],int):D=B[0];H=D+1
    else:D,H=C.slice_indices(B[0],0)
    if isinstance(B[1],int):E=B[1];I=E+1
    else:E,I=C.slice_indices(B[1],1)
    if type(A)==matrix:A=A.data
    elif type(A)not in[list,tuple]:A=[A]
    if not all([type(F)in stypes for F in A]):raise ValueError('Non numeric entry')
    else:
      G=0
      for F in range(D,H):
        for J in range(E,I):C.data[F*C.rstride+J*C.cstride]=C.dtype(A[G]);G=(G+1)%len(A)
  def __repr__(B):
    C=0
    for D in B.data:C=max(C,len(repr(D)))
    A='mat([';E=0
    for D in range(B.m):
      F=0;A=A+'['
      for H in range(B.n):
        G=repr(B.data[E+F]);A=A+G+' '*(C-len(G))
        if H<B.n-1:A=A+', '
        F=F+B.cstride
      if D<B.m-1:A=A+'],\n     '
      else:A=A+']'
      E=E+B.rstride
    A=A+'])';return A
  def __neg__(A):B=[A.data[C]*-1 for C in(range(len(A.data)))];return matrix(B,cstride=A.cstride,rstride=A.rstride)
  def __do_op__(C,a,b,op):
    B='division by zero';A=op
    if A=='+':return a+b
    elif A=='-':return a-b
    elif A=='*':return a*b
    elif A==_A:return a**b
    elif A=='/':
      try:return a/b
      except ZeroDivisionError:raise ZeroDivisionError(B)
    elif A==_B:
      try:return a//b
      except ZeroDivisionError:raise ZeroDivisionError(B)
    else:raise NotImplementedError('Unknown operator ',A)
  def __OP__(A,a,op):
    G='could not be broadcast';E=op
    if type(a)in stypes:F=[A.__do_op__(A.data[B],a,E)for B in(range(len(A.data)))];return matrix(F,cstride=A.cstride,rstride=A.rstride)
    elif type(a)==list:
      if A.n==1 and len(a)==A.m:return A.__OP__(matrix([a]).T,E)
      elif len(a)==A.n:return A.__OP__(matrix([a]),E)
      else:raise ValueError(G)
    elif type(a)==matrix:
      if A.m==a.m and A.n==a.n:F=[A.__do_op__(A[(B,C)],a[(B,C)],E)for B in(range(A.m))for C in(range(A.n))];return matrix(F,cstride=1,rstride=A.n)
      elif A.m==a.m:
        D=A.copy()
        for B in range(A.n):
          for C in range(A.m):D[(C,B)]=A.__do_op__(D[(C,B)],a[(C,0)],E)
        return D
      elif A.n==a.n:
        D=A.copy()
        for B in range(A.m):
          for C in range(A.n):D[(B,C)]=A.__do_op__(D[(B,C)],a[(0,C)],E)
        return D
      else:raise ValueError(G)
    raise NotImplementedError('__OP__ matrix + ',type(a))
  def __add__(A,a):return A.__OP__(a,'+')
  def __radd__(A,a):return A.__add__(a)
  def __sub__(A,a):
    if type(a)in estypes:return A.__add__(-a)
    raise NotImplementedError('__sub__ matrix -',type(a))
  def __rsub__(A,a):A=-A;return A.__add__(a)
  def __mul__(A,a):return A.__OP__(a,'*')
  def __rmul__(A,a):return A.__mul__(a)
  def __truediv__(A,a):return A.__OP__(a,'/')
  def __rtruediv__(A,a):return A.__OP__(a,'/')
  def __floordiv__(A,a):return A.__OP__(a,_B)
  def __rfloordiv__(A,a):return A.__OP__(a,_B)
  def __pow__(A,a):return A.__OP__(a,_A)
  def __rpow__(A,a):return A.__OP__(a,_A)
  def copy(A):return matrix([B for B in(A.data)],cstride=A.cstride,rstride=A.rstride)
  def size(A,axis=0):return[A.m*A.n,A.m,A.n][axis]
  @property
  def shape(self):return self.m,self.n
  @shape.setter
  def shape(self,nshape):
    B=nshape;A=self
    if B[0]*B[1]==A.size():A.m,A.n=B;A.cstride=1;A.rstride=A.n
    else:raise ValueError('total size of new matrix must be unchanged')
    return A
  @property
  def is_square(self):return self.m==self.n
  def reshape(B,nshape):A=B.copy();A.shape=nshape;return A
  @property
  def T(self):return self.transpose()
  def transpose(A):
    B=matrix(A.data,cstride=A.rstride,rstride=A.cstride)
    if A.cstride==A.rstride:B.shape=A.n,A.m
    return B
  def reciprocal(A,n=1):return matrix([n/B for B in(A.data)],cstride=A.cstride,rstride=A.rstride)
  def apply(A,func,*B,**C):return matrix([func(D,*B,**C)for D in(A.data)],cstride=A.cstride,rstride=A.rstride)
def matrix_isclose(x,y,rtol=1e-05,atol=flt_eps):
  for A in range(x.size()):
    try:B=[abs(x.data[A]-y.data[A])<=atol+rtol*abs(y.data[A])for A in(range(len(x.data)))]
    except (AttributeError,IndexError):B=[False for A in(range(len(x.data)))]
  return matrix(B,cstride=x.cstride,rstride=x.rstride,dtype=bool)
def matrix_equal(x,y,tol=0):
  A=False
  if type(y)==matrix:
    if x.shape==y.shape:A=all([abs(x.data[B]-y.data[B])<=tol for B in(range(x.size()))])
  return A
def matrix_equiv(x,y):
  A=False
  if type(y)==matrix:
    if x.size()==y.size():A=all([x.data[B]==y.data[B]for B in(range(len(x.data)))])
  return A
def fp_eps():
  A=1
  while 1+A>1:A=A/2
  return 2*A
flt_eps=fp_eps()
try:stypes.append(float);ddtype=float
except:pass
try:stypes.append(complex)
except:pass
estypes=[matrix]
estypes.extend(stypes)

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.