def get_new_tvec(self, iev):
        v1 = sp.ndarray(self.ndim, self.complex_precision)  # v1 = M^{-1}*r
        v2 = sp.ndarray(self.ndim, self.complex_precision)  # v2 = M^{-1}*u
        idx = 0

        # First half of vector
        for ii in range(self.nocc):
            for jj in range(self.nvirt):
                ediff = (self.evalai(ii, jj) - sp.real(self.teta[iev]))
                if np.abs(ediff) > 1e-8:
                    dtmp = 1 / ediff
                    v1[idx] = self.r_vecs[idx, iev] * dtmp
                    v2[idx] = self.u_vecs[idx, iev] * dtmp
                else:
                    print("Warning, (E_{a}-E_{i})<1e-8")
                    v1[idx] = self.complex_precision(
                        self.real_precision(0.0) + self.real_precision(0.0j))
                    v2[idx] = self.complex_precision(
                        self.real_precision(0.0) + self.real_precision(0.0j))
                idx += 1

        # Second half of vector
        for ii in range(self.nocc):
            for jj in range(self.nvirt):
                ediff = -self.evalai(ii, jj) - sp.real(self.teta[iev])
                if abs(ediff) > 1e-8:
                    dtmp = 1 / ediff
                    v1[idx] = self.r_vecs[idx, iev] * dtmp
                    v2[idx] = self.u_vecs[idx, iev] * dtmp
                else:
                    print("Warning, (E_{a}-E_{i})<1e-8")
                    v1[idx] = self.complex_precision(
                        self.real_precision(0.0) + self.real_precision(0.0j))
                    v2[idx] = self.complex_precision(
                        self.real_precision(0.0) + self.real_precision(0.0j))
                idx += 1

        sp.savetxt("v1_c" + str(self.cycle) + "_i" + str(iev + 1) + ".txt", v1)
        sp.savetxt("v2_c" + str(self.cycle) + "_i" + str(iev + 1) + ".txt", v2)

        u_m1_u = sp.vdot(self.u_vecs[:, iev], v2)
        print("u_m1_u = ", u_m1_u)
        if abs(u_m1_u) > 1e-8:
            u_m1_r = sp.vdot(self.u_vecs[:, iev], v1)
            print("u_m1_r = ", u_m1_r)
            factor = u_m1_r / sp.real(u_m1_u)
            return factor * v2 - v1
        else:
            return -v1
Example #2
0
def compute_loocv_gmm(variable,model,x,y,ids,K_u,alpha,beta,log_prop_u):
    """ Function that computes the estimation of the loocv for the GMM model with variables ids + variable(i)
        Inputs:
            model : the GMM model
            x,y : the training samples and the corresponding label
            ids : the pool of selected variables
            variable   : the variable to be tested from the set of available variable
            K_u    : the initial prediction values computed with all the samples
            alpha, beta and log_prop_u : constant that are computed outside of the loop to increased speed
        Outputs:
            loocv_temp : the loocv
            
        Used in GMM.forward_selection()
    """
    n = x.shape[0]
    ids.append(variable)      # Iteratively add one of the remaining variables
    Kp = model.predict_gmm(x,ids=ids)[1]# Predict with all the samples with ids
    loocv_temp=0.0;                     # Initialization of the temporary loocv
    for j in range(n):                  # Predict the class with the model ids_t
        Kloo = Kp[j,:] + K_u  # Initialization of the decision rule for sample "j" #--- Change for only not C---#
                   
        c = int(y[j]-1)        # Update of parameter of class c
        m  = (model.ni[c]*model.mean[c,ids] -x[j,ids])*alpha[c]    # Update the mean value
        xb = x[j,ids] - m                                     # x centered
        cov_u =  (model.cov[c,ids,:][:,ids] - sp.outer(xb,xb)*alpha[c])*beta    # Update the covariance matrix 
        logdet,rcond = safe_logdet(cov_u)
        Kloo[c] =   logdet - 2*log_prop_u[c] + sp.vdot(xb,mylstsq(cov_u,xb.T,rcond))    # Compute the new decision rule
        del cov_u,xb,m,c                   
                    
        yloo = sp.argmin(Kloo)+1
        loocv_temp += float(yloo==y[j])                   # Check the correct/incorrect classification rule
    ids.pop()                                                         # Remove the current variable 
    return loocv_temp/n                                           # Compute loocv for variable 
Example #3
0
def FIRE(x0,
         fprime,
         fmax=0.005,
         Nmin=5.,
         finc=1.1,
         fdec=0.5,
         alphastart=0.1,
         fa=0.99,
         deltatmax=10.,
         maxsteps=10**5):

    Nmin, finc, fdec, alphastart, fa, deltatmax = (5., 1.1, 0.5, 0.1, 0.99,
                                                   10.)

    alpha = alphastart
    deltat = 0.1

    pos = x0.copy()
    v = sp.zeros_like(pos)

    steps_since_negative = 0

    def norm(vec):
        return sp.sqrt(sp.sum(vec**2, 1))

    def unitize(vec):
        return ((vec.T) / norm(vec)).T

    forces = fprime(pos)

    step_num = 0

    while max(norm(forces)) > fmax and step_num < maxsteps:
        forces = fprime(pos)
        power = sp.vdot(forces, v)

        print "Step: {}, max_force: {}, power: {}".format(
            step_num, max(norm(forces)), power)

        v = (1.0 - alpha) * v + alpha * (norm(v) * unitize(forces).T).T

        if power > 0.:
            if steps_since_negative > Nmin:
                deltat = min(deltat * finc, deltatmax)
                alpha = alpha * fa
            steps_since_negative += 1

        else:
            steps_since_negative = 0

            deltat = deltat * fdec
            v *= 0.
            alpha = alphastart

        v += forces * deltat
        pos += v * deltat
        step_num += 1

    return pos
Example #4
0
def GetProbabilities(n, Psi):
    """
    Get probabilites by doing mod-squared of @Psi.
    """
    density = sp.zeros(2**n)
    for i in range(2**n): 
        density[i] = sp.vdot(Psi[i], Psi[i]).real
    return density
Example #5
0
def ConstructOverlapData(t, Psi, vec):
    """ 
    Construct proper datapoint for overlap. 
    """
    datapoint = [t]
    overlap = abs(sp.vdot(Psi, vec))**2
    datapoint.append(overlap)
    return datapoint
Example #6
0
def ConstructOverlapData(t, Psi, vec):
    """ 
    Construct proper datapoint for overlap. 
    """
    datapoint = [t]
    overlap = abs(sp.vdot(Psi, vec)) ** 2
    datapoint.append(overlap)
    return datapoint
Example #7
0
def GetProbabilities(n, Psi):
    """
    Get probabilites by doing mod-squared of @Psi.
    """
    density = sp.zeros(2**n)
    for i in range(2**n):
        density[i] = sp.vdot(Psi[i], Psi[i]).real
    return density
Example #8
0
    def fire(self,fmax=0.1,
            Nmin=5.,finc=1.1,fdec=0.5,alphastart=0.1,fa=0.99,deltatmax=10.,
            maxsteps = 10**5):
        """ Do a fire relaxation """

        alpha = alphastart
        deltat = 0.1

        pos = self.get_pos_arr(force=True)
        v = sp.zeros_like(pos)
        self._update_vel(v)

        v = self._get_vel_arr()

        steps_since_negative = 0

        def norm_arr(vec):
            return sp.sqrt(sp.sum(vec**2,1))
        def unitize_arr(vec):
            return ((vec.T)/norm(vec)).T

        forces = sp.nan_to_num(sp.array([ [sp.inf,sp.inf]]))

        step_num = 0

        print "Beginning FIRE Relaxation -- fmax={}".format(fmax)

        while max(norm_arr(forces)) > fmax and step_num < maxsteps:
            forces = self.forces

            power = sp.vdot(forces,v)
            print "Step: {}, max_force: {}, power: {}".format(step_num,max(norm_arr(forces)), power)

            v = (1.0 - alpha)*v + alpha*(norm_arr(v)*unitize_arr(forces).T).T

            if power>0.:
                if steps_since_negative > Nmin:
                    deltat = min(deltat * finc, deltatmax)
                    alpha = alpha*fa
                steps_since_negative += 1

            else:
                steps_since_negative = 0

                deltat = deltat * fdec
                v *= 0.
                alpha = alphastart

            v += forces*deltat
            pos += v*deltat
            self._update_pos(pos)
            step_num += 1
        
        self._update_pos(pos)
        self._update_vel(v)
        print "Relaxation finished..."
Example #9
0
    def fire(self,fmax=0.1,
            Nmin=5.,finc=1.1,fdec=0.5,alphastart=0.1,fa=0.99,deltatmax=10.,
            maxsteps = 10**5):
        """ Do a fire relaxation """

        alpha = alphastart
        deltat = 0.1

        pos = self.get_pos_arr(force=True)
        v = sp.zeros_like(pos)
        self._update_vel(v)

        v = self._get_vel_arr()

        steps_since_negative = 0

        def norm_arr(vec):
            return sp.sqrt(sp.sum(vec**2,1))
        def unitize_arr(vec):
            return ((vec.T)/norm(vec)).T

        forces = sp.nan_to_num(sp.array([ [sp.inf,sp.inf]]))

        step_num = 0

        print "Beginning FIRE Relaxation -- fmax={}".format(fmax)

        while max(norm_arr(forces)) > fmax and step_num < maxsteps:
            forces = self.forces

            power = sp.vdot(forces,v)
            print "Step: {}, max_force: {}, power: {}".format(step_num,max(norm_arr(forces)), power)

            v = (1.0 - alpha)*v + alpha*(norm_arr(v)*unitize_arr(forces).T).T

            if power>0.:
                if steps_since_negative > Nmin:
                    deltat = min(deltat * finc, deltatmax)
                    alpha = alpha*fa
                steps_since_negative += 1

            else:
                steps_since_negative = 0

                deltat = deltat * fdec
                v *= 0.
                alpha = alphastart

            v += forces*deltat
            pos += v*deltat
            self._update_pos(pos)
            step_num += 1
        
        self._update_pos(pos)
        self._update_vel(v)
        print "Relaxation finished..."
Example #10
0
def ConstructFidelityData(Psi, vecs, T, outdir):
    """
    Output the fidelity for multi-T simulations by calculating \
    the overlap between however many eigenstates we want. 
    """
    data = []
    for i in range(0, len(vecs)):
        overlap = abs(sp.vdot(Psi, vecs[i])) ** 2
        data.append([T, overlap])
    return data
Example #11
0
def ConstructFidelityData(Psi, vecs, T, outdir):
    """
    Output the fidelity for multi-T simulations by calculating \
    the overlap between however many eigenstates we want. 
    """
    data = []
    for i in range(0, len(vecs)):
        overlap = abs(sp.vdot(Psi, vecs[i]))**2
        data.append([T, overlap])
    return data
Example #12
0
def CheckNorm(t, nQubits, Psi, Hvecs, eps):
    """ 
    Check for numerical error with normalization. 
    """
    norm = 0.0

    for i in range(0, 2**nQubits): 
        norm += abs(sp.vdot(Psi, Hvecs[:,i]))**2

    if (1.0 - norm) > eps:
        print (str((1.0 - norm)) + " (norm error) > " + str(eps) + 
               " (eps) @ t = " + str(t))
Example #13
0
def FIRE(x0,fprime,fmax=0.005,
            Nmin=5.,finc=1.1,fdec=0.5,alphastart=0.1,fa=0.99,deltatmax=10.,
            maxsteps = 10**5):

    Nmin,finc,fdec,alphastart,fa,deltatmax=(5.,1.1,0.5,0.1,0.99,10.)

    alpha = alphastart
    deltat = 0.1

    pos = x0.copy()
    v = sp.zeros_like(pos)

    steps_since_negative = 0

    def norm(vec):
        return sp.sqrt(sp.sum(vec**2,1))
    def unitize(vec):
        return ((vec.T)/norm(vec)).T

    forces = fprime(pos)

    step_num = 0

    while max(norm(forces)) > fmax and step_num < maxsteps:
        forces = fprime(pos)
        power = sp.vdot(forces,v)

        print "Step: {}, max_force: {}, power: {}".format(step_num,max(norm(forces)), power)

        v = (1.0 - alpha)*v + alpha*(norm(v)*unitize(forces).T).T

        if power>0.:
            if steps_since_negative > Nmin:
                deltat = min(deltat * finc, deltatmax)
                alpha = alpha*fa
            steps_since_negative += 1

        else:
            steps_since_negative = 0

            deltat = deltat * fdec
            v *= 0.
            alpha = alphastart

        v += forces*deltat
        pos += v*deltat
        step_num += 1
    
    return pos

    
def get_reciprocal(positions, dihedral_atoms):
    """
    In dihedral angle calculation, see if angle is the reciprocal or not.
    """
    ii, jj, kk, ll = dihedral_atoms
    # vector 0->1, 1->2, 2->3 and their normalized cross products:
    a = positions[jj] - positions[ii]
    b = positions[kk] - positions[jj]
    c = positions[ll] - positions[kk]
    bxa = sp.cross(b, a)
    if sp.vdot(bxa, c) > 0:
        return True
    else:
        return False
Example #15
0
def compute_loocv_gmm(variable, model, x, y, ids, K_u, alpha, beta,
                      log_prop_u):
    """ Function that computes the estimation of the loocv for the GMM model with variables ids + variable(i)
        Inputs:
            model : the GMM model
            x,y : the training samples and the corresponding label
            ids : the pool of selected variables
            variable   : the variable to be tested from the set of available variable
            K_u    : the initial prediction values computed with all the samples
            alpha, beta and log_prop_u : constant that are computed outside of the loop to increased speed
        Outputs:
            loocv_temp : the loocv
            
        Used in GMM.forward_selection()
    """
    n = x.shape[0]
    ids.append(variable)  # Iteratively add one of the remaining variables
    Kp = model.predict_gmm(x,
                           ids=ids)[1]  # Predict with all the samples with ids
    loocv_temp = 0.0
    # Initialization of the temporary loocv
    for j in range(n):  # Predict the class with the model ids_t
        Kloo = Kp[
            j, :] + K_u  # Initialization of the decision rule for sample "j" #--- Change for only not C---#

        c = int(y[j] - 1)  # Update of parameter of class c
        m = (model.ni[c] * model.mean[c, ids] -
             x[j, ids]) * alpha[c]  # Update the mean value
        xb = x[j, ids] - m  # x centered
        cov_u = (model.cov[c, ids, :][:, ids] - sp.outer(xb, xb) *
                 alpha[c]) * beta  # Update the covariance matrix
        logdet, rcond = safe_logdet(cov_u)
        Kloo[c] = logdet - 2 * log_prop_u[c] + sp.vdot(
            xb, mylstsq(cov_u, xb.T, rcond))  # Compute the new decision rule
        del cov_u, xb, m, c

        yloo = sp.argmin(Kloo) + 1
        loocv_temp += float(
            yloo == y[j])  # Check the correct/incorrect classification rule
    ids.pop()  # Remove the current variable
    return loocv_temp / n  # Compute loocv for variable
    def build_subspace_matrix(self):
        sb_dim = 0
        for vs in [
                self.vspace_r, self.vspace_l, self.vspace_rp, self.vspace_lp
        ]:
            if vs is not None:
                sb_dim = sb_dim + vs.shape[1]
        submat = sp.zeros((sb_dim, sb_dim), self.complex_precision)

        if self.vspace_r is not None:
            print("self.vspace_r.shape = ", self.vspace_r.shape)
        if self.vspace_l is not None:
            print("self.vspace_l.shape = ", self.vspace_l.shape)
        if self.vspace_rp is not None:
            print("self.vspace_rp.shape = ", self.vspace_rp.shape)
        if self.vspace_lp is not None:
            print("self.vspace_lp.shape = ", self.vspace_lp.shape)

        print("sb_dim = ", sb_dim)

        vi = 0
        for vs in [
                self.vspace_r, self.vspace_l, self.vspace_rp, self.vspace_lp
        ]:
            if vs is not None:
                for ii in range(vs.shape[1]):
                    wj = 0
                    for ws in [
                            self.wspace_r, self.wspace_l, self.wspace_rp,
                            self.wspace_lp
                    ]:
                        if ws is not None:
                            for jj in range(ws.shape[1]):
                                submat[vi + ii, wj + jj] = sp.vdot(
                                    vs[:, ii], ws[:, jj])
                            wj = wj + ws.shape[1]
                vi = vi + vs.shape[1]
        return submat
Example #17
0
def gexpmv(A, v, t, anorm, m=None, tol=0.0, w=None, verbose=False, mxstep=500, break_tol=None):
      mxreject = 0 #matlab version has this set to 10
      delta = 1.2
      gamma = 0.9

      if break_tol is None:
            #break_tol = tol  
            break_tol = anorm*tol

      n = A.shape[0]

      if hasattr(A, "matvec"):
            matvec = A.matvec
      else:
            matvec = lambda v: sp.dot(A,v)

      if m is None:
            m = min(20, n-1)
      
      if len(A.shape) != 2 or A.shape[0] != A.shape[1]:
            raise ValueError("A is not a square matrix")
      
      if m >= n or m <= 0:
            raise ValueError("m is invalid")

      k1 = 2
      mh = m + 2

      ibrkflag = 0
      mbrkdwn  = m
      nmult    = 0
      nreject  = 0
      nexph    = 0
      nscale   = 0

      t_out    = abs( t )
      tbrkdwn  = 0.0
      step_min = t_out
      step_max = 0.0
      nstep    = 0
      s_error  = 0.0
      x_error  = 0.0
      t_now    = 0.0
      t_new    = 0.0
      
      eps = sp.finfo(A.dtype).eps
      rndoff = eps*anorm

      sgn = sp.sign(t)

      if w is None: #allow supplying a starting vector
            w = v.copy()
      else:
            w[:] = v
            
      beta = la.norm(w)
      vnorm = beta
      hump = beta 

      #obtain the very first stepsize ...

      SQR1 = sqrt( 0.1 )
      xm = 1.0/m
      p2 = tol*(((m+1)/sp.e)**(m+1)) * sqrt(2.0*sp.pi*(m+1))
      t_new = (1.0/anorm) * (p2 / (4.0*beta*anorm))**xm
      p1 = 10.0**(round( log10( t_new )-SQR1 )-1)
      t_new = trunc( t_new/p1 + 0.55 ) * p1

      #step-by-step integration ...
      while t_now < t_out:

            nstep = nstep + 1
            t_step = min( t_out-t_now, t_new )

            #initialize Krylov subspace
            vs = sp.zeros((m+2,n), A.dtype)
            vs[0,:] = w / beta

            H = sp.zeros((mh,mh), A.dtype)

            #Arnoldi loop ...
            for j in range(1,m+1):
                  nmult = nmult + 1
                  vs[j,:] = matvec(vs[j-1,:])

                  for i in range(1,j+1):
                        #Compute overlaps of new vector Av with all other Kyrlov vectors
                        #(these are elements of an upper Hessenberg matrix)
                        hij = sp.vdot(vs[i-1,:], vs[j,:])
                        vs[j,:] -= hij * vs[i-1,:] #orthogonalize new vector. maybe switch to axpy
                        H[i-1,j-1] = hij #store matrix element

                  hj1j = la.norm( vs[j,:] )
                  #if the orthogonalized Krylov vector is zero, stop!
                  if hj1j <= break_tol:
                        if verbose:
                              print('breakdown: mbrkdwn =',j,' h =',hj1j)
                        k1 = 0
                        ibrkflag = 1
                        mbrkdwn = j
                        tbrkdwn = t_now
                        t_step = t_out-t_now
                        break

                  H[j,j-1] = hj1j
                  vs[j,:] *= 1.0/hj1j

            if ibrkflag == 0: #if we didn't break down
                  nmult = nmult + 1
                  vs[m+1,:] = matvec(vs[m,:])
                  avnorm = la.norm( vs[m+1,:] )

            #Orig: set 1 for the 2-corrected scheme
            H[m+1, m] = 1.0

            #loop while ireject<mxreject until the tolerance is reached
            ireject = 0

            #compute w = beta*V*exp(t_step*H)*e1 ...

            #First compute expH for a good step size
            while True:
                  nexph = nexph + 1
                  mx = mbrkdwn + k1 #max(mx) = m+2
                  #irreducible rational Pade approximation. scipy's implementation automatically chooses an order
                  expH = la.expm(sgn * t_step * H[:mx,:mx])
                  #nscale = nscale + ns #don't have this info
                  
                  #local error estimation
                  if k1 == 0: #if breakdown has occured (the Krylov subspace is complete)
                        err_loc = tol #matlab uses break_tol
                  else:
                        p1 = abs( expH[m,0] ) * beta #wsp(iexph+m) 
                        p2 = abs( expH[m+1,0] ) * beta * avnorm #avnorm is defined when k1 != 0
                        if p1 > 10.0*p2:
                              err_loc = p2
                              xm = 1.0/m
                        elif p1 > p2:
                              err_loc = (p1*p2)/(p1-p2)
                              xm = 1.0/m
                        else:
                              err_loc = p1
                              xm = 1.0/(m-1)

                  #reject the step-size if the error is not acceptable ...

                  if ( (k1 != 0) and (err_loc > delta*t_step*tol) and
                  (mxreject == 0 or ireject < mxreject) ):
                        t_old = t_step
                        t_step = gamma * t_step * (t_step*tol/err_loc)**xm
                        p1 = 10.0**(round( log10( t_step )-SQR1 )-1)
                        t_step = trunc( t_step/p1 + 0.55 ) * p1
                        if verbose:
                              print('t_step = ',t_old)
                              print('err_loc = ',err_loc)
                              print('err_required = ',delta*t_old*tol)
                              print('stepsize rejected, stepping down to: ',t_step)

                        ireject = ireject + 1
                        nreject = nreject + 1
                        if mxreject != 0 and ireject > mxreject:
                              print("Failure in gexpmv: ---")
                              print("The requested tolerance is too high.")
                              print("Rerun with a smaller value.")
                              iflag = 2
                              return
                  else:
                        break #step size OK (happens after a breakdown)

            #now update w = beta*V*exp(t_step*H)*e1 and the hump ...
            mx = mbrkdwn + max( 0, k1-1 ) #max(mx) = m+1
            w = beta * vs[:mx,:].T.dot(expH[:mx,0])
            beta = la.norm(w)
            hump = max( hump, beta )

            #suggested value for the next stepsize ...

            t_new = gamma * t_step * (t_step*tol/err_loc)**xm
            p1 = 10.0**(round( log10( t_new )-SQR1 )-1)
            t_new = trunc( t_new/p1 + 0.55 ) * p1

            err_loc = max( err_loc, rndoff )

            #update the time covered ...

            t_now = t_now + t_step

            #display and keep some information ...

            if verbose:
                  print('integration ', nstep, ' ---------------------------------')
                  #print('scale-square = ', nscale)
                  print('step_size = ', t_step)
                  print('err_loc   = ',err_loc)
                  print('next_step = ',t_new)

            step_min = min( step_min, t_step )
            step_max = max( step_max, t_step )
            s_error = s_error + err_loc
            x_error = max( x_error, err_loc )

            if mxstep == 0 or nstep < mxstep:
                  continue
            iflag = 1
            break

      return w, nstep < mxstep, nstep, ibrkflag==1, mbrkdwn
def vlen(v):
    return math.sqrt(scipy.vdot(v, v))
B = 1
r = 0.06
T = 1
K = 50


def f(x, strike):
    return max(x - strike, 0)


m = scipy.array([[S * (1 - down), B * scipy.exp(r * T)],
                 [S * (1 + up), B * scipy.exp(r * T)]])
payoff = scipy.array([f(S * (1 - down), K), f(S * (1 + up), K)])

portfolio = scipy.linalg.solve(m, payoff)
value = scipy.vdot(portfolio, scipy.array([S, B]))

print('portfolio: phi=', portfolio[0], 'psi=', portfolio[1], '\n')
print('derivative value: ', value, '\n')

## NAME:  singleperiod.py
## USAGE: From shell prompt: python3 singleperiod.py
##        or within interactive python3 environment, import filename
## REQUIRED ARGUMENTS: none
## OPTIONS: none
## DESCRIPTION: Set up and solve for the replicating portfolio
## and the value of the corresponding derivative security in a
## single period binomial model.
## DIAGNOSTICS: none
## CONFIGURATION AND ENVIRONMENT:
## DEPENDENCIES: Scientific python
Example #20
0
def vlen(v):
	return math.sqrt(scipy.vdot(v, v))
Example #21
0
def gexpmv(A,
           v,
           t,
           anorm,
           m=None,
           tol=0.0,
           w=None,
           verbose=False,
           itrace=0,
           mxstep=500,
           break_tol=None):
    mxreject = 0
    delta = 1.2
    gamma = 0.9

    if break_tol is None:
        #break_tol = tol
        break_tol = anorm * tol

    n = A.shape[0]

    if hasattr(A, "matvec"):
        matvec = A.matvec
    else:
        matvec = lambda v: sp.dot(A, v)

    if m is None:
        m = min(20, n - 1)

    if len(A.shape) != 2 or A.shape[0] != A.shape[1]:
        raise ValueError("A is not a square matrix")

    if m >= n or m <= 0:
        raise ValueError("m is invalid")

    k1 = 2
    mh = m + 2

    ibrkflag = 0
    mbrkdwn = m
    nmult = 0
    nreject = 0
    nexph = 0
    nscale = 0

    t_out = abs(t)
    tbrkdwn = 0.0
    step_min = t_out
    step_max = 0.0
    nstep = 0
    s_error = 0.0
    x_error = 0.0
    t_now = 0.0
    t_new = 0.0

    avnorm = 0.0  #I think the EXPOKIT source relied on this being initialized to zero by the compiler

    #pretty sure this just computes machine epsilon
    eps = 0.0
    p1 = 4.0 / 3.0
    while eps == 0.0:
        p2 = p1 - 1.0
        p3 = 3 * p2
        eps = abs(p3 - 1.0)
    if tol <= eps:
        tol = sqrt(eps)
    rndoff = eps * anorm

    sgn = copysign(1.0, t)
    if w is None:  #allow supplying a starting vector
        w = v.copy()
    else:
        w[:] = v

    beta = la.norm(w)
    vnorm = beta
    hump = beta

    #obtain the very first stepsize ...

    SQR1 = sqrt(0.1)
    xm = 1.0 / m
    p2 = tol * (((m + 1) / sp.e)**(m + 1)) * sqrt(2.0 * sp.pi * (m + 1))
    t_new = (1.0 / anorm) * (p2 / (4.0 * beta * anorm))**xm
    p1 = 10.0**(round(log10(t_new) - SQR1) - 1)
    t_new = trunc(t_new / p1 + 0.55) * p1

    #step-by-step integration ...
    while t_now < t_out:

        nstep = nstep + 1
        t_step = min(t_out - t_now, t_new)

        #initialize Krylov subspace
        vs = sp.zeros((m + 2, n), A.dtype)
        vs[0, :] = w / beta

        H = sp.zeros((mh, mh), A.dtype)

        #Arnoldi loop ...
        for j in range(1, m + 1):
            nmult = nmult + 1
            vs[j, :] = matvec(vs[j - 1, :])

            for i in range(1, j + 1):
                #Compute overlaps of new vector Av with all other Kyrlov vectors
                #(these are elements of an upper Hessenberg matrix)
                hij = sp.vdot(vs[i - 1, :], vs[j, :])
                vs[j, :] -= hij * vs[
                    i - 1, :]  #orthogonalize new vector. maybe switch to axpy
                H[i - 1, j - 1] = hij  #store matrix element

            hj1j = la.norm(vs[j, :])
            #if the orthogonalized Krylov vector is zero, stop!
            if hj1j <= break_tol:
                print('breakdown: mbrkdwn =', j, ' h =', hj1j)
                k1 = 0
                ibrkflag = 1
                mbrkdwn = j
                tbrkdwn = t_now
                t_step = t_out - t_now
                break

            H[j, j - 1] = hj1j
            vs[j, :] *= 1.0 / hj1j

        if ibrkflag == 0:  #if we didn't break down
            nmult = nmult + 1
            vs[m + 1, :] = matvec(vs[m, :])
            avnorm = la.norm(vs[m + 1, :])

        #Orig: set 1 for the 2-corrected scheme
        H[m + 1, m] = 1.0

        #loop while ireject<mxreject until the tolerance is reached
        ireject = 0

        #compute w = beta*V*exp(t_step*H)*e1 ...

        #First compute expH for a good step size
        while True:
            nexph = nexph + 1
            mx = mbrkdwn + k1  #max(mx) = m+2
            #irreducible rational Pade approximation. scipy's implementation automatically chooses an order
            expH = la.expm(sgn * t_step * H[:mx, :mx])
            #nscale = nscale + ns #don't have this info

            #local error estimation
            if k1 == 0:
                err_loc = tol
            else:
                p1 = abs(expH[m, 0]) * beta  #wsp(iexph+m)
                p2 = abs(
                    expH[m + 1, 0]
                ) * beta * avnorm  #FIXME: avnorm is not always defined....
                if p1 > 10.0 * p2:
                    err_loc = p2
                    xm = 1.0 / m
                elif p1 > p2:
                    err_loc = (p1 * p2) / (p1 - p2)
                    xm = 1.0 / m
                else:
                    err_loc = p1
                    xm = 1.0 / (m - 1)

            #reject the step-size if the error is not acceptable ...

            if ((k1 != 0) and (err_loc > delta * t_step * tol)
                    and (mxreject == 0 or ireject < mxreject)):
                t_old = t_step
                t_step = gamma * t_step * (t_step * tol / err_loc)**xm
                p1 = 10.0**(round(log10(t_step) - SQR1) - 1)
                t_step = trunc(t_step / p1 + 0.55) * p1
                if verbose:
                    print('t_step = ', t_old)
                    print('err_loc = ', err_loc)
                    print('err_required = ', delta * t_old * tol)
                    print('stepsize rejected, stepping down to: ', t_step)

                ireject = ireject + 1
                nreject = nreject + 1
                if mxreject != 0 and ireject > mxreject:
                    print("Failure in ZGEXPV: ---")
                    print("The requested tolerance is too high.")
                    print("Rerun with a smaller value.")
                    iflag = 2
                    return
            else:
                break  #step size OK

        #now update w = beta*V*exp(t_step*H)*e1 and the hump ...
        mx = mbrkdwn + max(0, k1 - 1)  #max(mx) = m+1
        w = beta * vs[:mx, :].T.dot(expH[:mx, 0])
        beta = la.norm(w)
        hump = max(hump, beta)

        #suggested value for the next stepsize ...

        t_new = gamma * t_step * (t_step * tol / err_loc)**xm
        p1 = 10.0**(round(log10(t_new) - SQR1) - 1)
        t_new = trunc(t_new / p1 + 0.55) * p1

        err_loc = max(err_loc, rndoff)

        #update the time covered ...

        t_now = t_now + t_step

        #display and keep some information ...

        if itrace != 0:
            print('integration ', nstep, ' ---------------------------------')
            #print('scale-square = ', nscale)
            print('step_size = ', t_step)
            print('err_loc   = ', err_loc)
            print('next_step = ', t_new)

        step_min = min(step_min, t_step)
        step_max = max(step_max, t_step)
        s_error = s_error + err_loc
        x_error = max(x_error, err_loc)

        if mxstep == 0 or nstep < mxstep:
            continue
        iflag = 1
        break

    return w, nstep < mxstep, nstep, ibrkflag == 1, mbrkdwn