def test_kron(self): a = sparsify(DM([[1, 0, 6], [2, 7, 0]])) b = sparsify(DM([[1, 0, 0], [2, 3, 7], [0, 0, 9], [1, 12, 13]])) c_ = c.kron(a.sparsity(), b.sparsity()) self.assertEqual(c_.size1(), a.size1() * b.size1()) self.assertEqual(c_.size2(), a.size2() * b.size2()) self.assertEqual(c_.nnz(), a.nnz() * b.nnz()) self.checkarray(IM(c_, 1), IM(c.kron(a, b).sparsity(), 1))
def test_kron(self): a = sparsify(DM([[1,0,6],[2,7,0]])) b = sparsify(DM([[1,0,0],[2,3,7],[0,0,9],[1,12,13]])) c_ = c.kron(a.sparsity(),b.sparsity()) self.assertEqual(c_.size1(),a.size1()*b.size1()) self.assertEqual(c_.size2(),a.size2()*b.size2()) self.assertEqual(c_.nnz(),a.nnz()*b.nnz()) self.checkarray(IM(c_,1),IM(c.kron(a,b).sparsity(),1))
def test_cle_small(self): for Solver, options in clesolvers: for n in [2, 3, 4]: numpy.random.seed(1) print(n) A_ = DMatrix(numpy.random.random((n, n))) v = DMatrix(numpy.random.random((n, n))) V_ = mul(v, v.T) solver = CleSolver( Solver, cleStruct(a=Sparsity.dense(n, n), v=Sparsity.dense(n, n))) solver.setOption(options) solver.init() solver.setInput(A_, "a") solver.setInput(V_, "v") As = MX.sym("A", n, n) Vs = MX.sym("V", n, n) Vss = (Vs + Vs.T) / 2 e = DMatrix.eye(n) A_total = -c.kron(e, As) - c.kron(As, e) Pf = solve(A_total, vec(Vss), "csparse") refsol = MXFunction(dleIn(a=As, v=Vs), dleOut(p=Pf.reshape((n, n)))) refsol.init() refsol.setInput(A_, "a") refsol.setInput(V_, "v") solver.evaluate() X = solver.getOutput() refsol.evaluate() Xref = refsol.getOutput() a0 = mul([A_, X]) + mul([X, A_.T]) + V_ a0ref = mul([A_, Xref]) + mul([Xref, A_.T]) + V_ self.checkarray(a0, a0ref) self.checkarray(a0, DMatrix.zeros(n, n)) self.checkfunction(solver, refsol, sens_der=True, hessian=True, evals=2)
def test_cle_small(self): for Solver, options in clesolvers: for n in [2,3,4]: numpy.random.seed(1) print (n) A_ = DMatrix(numpy.random.random((n,n))) v = DMatrix(numpy.random.random((n,n))) V_ = mul(v,v.T) solver = CleSolver(Solver,cleStruct(a=Sparsity.dense(n,n),v=Sparsity.dense(n,n))) solver.setOption(options) solver.init() solver.setInput(A_,"a") solver.setInput(V_,"v") As = MX.sym("A",n,n) Vs = MX.sym("V",n,n) Vss = (Vs+Vs.T)/2 e = DMatrix.eye(n) A_total = - c.kron(e,As) - c.kron(As,e) Pf = solve(A_total,vec(Vss),"csparse") refsol = MXFunction(dleIn(a=As,v=Vs),dleOut(p=Pf.reshape((n,n)))) refsol.init() refsol.setInput(A_,"a") refsol.setInput(V_,"v") solver.evaluate() X = solver.getOutput() refsol.evaluate() Xref = refsol.getOutput() a0 = mul([A_,X]) + mul([X,A_.T])+V_ a0ref = mul([A_,Xref]) + mul([Xref,A_.T])+V_ self.checkarray(a0,a0ref) self.checkarray(a0,DMatrix.zeros(n,n)) self.checkfunction(solver,refsol,sens_der=True,hessian=True,evals=2)
def test_dle_small(self): for Solver, options in dlesolvers: for n in [2,3,4]: numpy.random.seed(1) print (n) r = 0.8 A_ = tril(DMatrix(numpy.random.random((n,n)))) for i in range(n): A_[i,i] = numpy.random.random()*r*2-r Q = scipy.linalg.orth(numpy.random.random((n,n))) A_ = mul([Q,A_,Q.T]) v = DMatrix(numpy.random.random((n,n))) V_ = mul(v,v.T) solver = DleSolver("solver", Solver,{'a':Sparsity.dense(n,n),'v':Sparsity.dense(n,n)}, options) solver.setInput(A_,"a") solver.setInput(V_,"v") As = MX.sym("A",n,n) Vs = MX.sym("V",n,n) Vss = (Vs+Vs.T)/2 A_total = DMatrix.eye(n*n) - c.kron(As,As) Pf = solve(A_total,vec(Vss),"csparse") refsol = MXFunction("refsol", dleIn(a=As,v=Vs),dleOut(p=Pf.reshape((n,n)))) refsol.setInput(A_,"a") refsol.setInput(V_,"v") solver.evaluate() X = solver.getOutput() refsol.evaluate() Xref = refsol.getOutput() a0 = (mul([A_,X,A_.T])+V_) a0ref = (mul([A_,Xref,A_.T])+V_) a1 = X a1ref = Xref self.checkarray(a0ref,a1ref) self.checkarray(a0,a1) try: self.checkfunction(solver,refsol,sens_der=True,hessian=True,evals=2,failmessage=str(Solver)) except Exception as e: if "second order derivatives are not supported" in str(e): self.checkfunction(solver,refsol,evals=1,hessian=False,sens_der=False,failmessage=str(Solver)) else: raise e
def test_kron(self): a = sparsify(DMatrix([[1, 0, 6], [2, 7, 0]])) b = sparsify(DMatrix([[1, 0, 0], [2, 3, 7], [0, 0, 9], [1, 12, 13]])) c_ = c.kron(a, b) self.assertEqual(c_.size1(), a.size1() * b.size1()) self.assertEqual(c_.size2(), a.size2() * b.size2()) self.assertEqual(c_.nnz(), a.nnz() * b.nnz()) self.checkarray(c_, numpy.kron(a, b))
def test_kron(self): a = sparse(DMatrix([[1, 0, 6], [2, 7, 0]])) b = sparse(DMatrix([[1, 0, 0], [2, 3, 7], [0, 0, 9], [1, 12, 13]])) c_ = c.kron(a, b) self.assertEqual(c_.size1(), a.size1() * b.size1()) self.assertEqual(c_.size2(), a.size2() * b.size2()) self.assertEqual(c_.size(), a.size() * b.size()) self.checkarray(c_, numpy.kron(a, b))
def test_dple_small(self): for Solver, options in dplesolvers: for K in ([3,4] if args.run_slow else [2,3]): for n in [2,3,4]: print (Solver, options) numpy.random.seed(1) print (n,K) A_ = [randstable(n) for i in range(K)] V_ = [mtimes(v,v.T) for v in [DM(numpy.random.random((n,n))) for i in range(K)]] V2_ = [mtimes(v,v.T) for v in [DM(numpy.random.random((n,n))) for i in range(K)]] S = kron(Sparsity.diag(K),Sparsity.dense(n,n)) solver = dplesol("solver", Solver,{'a':S,'v':repmat(S,1,2)}, options) inputs = {"a":dcat(A_), "v": horzcat(dcat(V_),dcat(V2_))} As = MX.sym("A",S) Vs = MX.sym("V",S) def sigma(a): return a[1:] + [a[0]] def isigma(a): return [a[-1]] + a[:-1] Vss = hcat([(i+i.T)/2 for i in isigma(list(diagsplit(Vs,n))) ]) AA = dcat([c.kron(i,i) for i in diagsplit(As,n)]) A_total = DM.eye(n*n*K) - vertcat(*[AA[-n*n:,:],AA[:-n*n,:]]) Pf = solve(A_total,vec(Vss),"csparse") P = Pf.reshape((n,K*n)) P = dcat(horzsplit(P,n)) refsol = Function("refsol", {"a": As,"v":Vs,"p":P},dple_in(),dple_out()).map("map","serial",2,["a"],[]) self.checkfunction(solver,refsol,inputs=inputs,failmessage=str(Solver))
def test_dple_alt_small(self): for Solver, options in dplesolvers: for K in ([3,4] if args.run_slow else [2,3]): for n in [2,3,4]: print (Solver, options) numpy.random.seed(1) print (n,K) A_ = [randstable(n) for i in range(K)] V_ = [mtimes(v,v.T) for v in [DM(numpy.random.random((n,n))) for i in range(K)]] inputs = {"a":hcat(A_), "v": hcat(V_)} As = MX.sym("A",n,n*K) Vs = MX.sym("V",n,n*K) def sigma(a): return a[1:] + [a[0]] def isigma(a): return [a[-1]] + a[:-1] Vss = hcat([(i+i.T)/2 for i in isigma(list(horzsplit(Vs,n))) ]) AA = dcat([c.kron(i,i) for i in horzsplit(As,n)]) A_total = DM.eye(n*n*K) - vcat([AA[-n*n:,:],AA[:-n*n,:]]) Pf = solve(A_total,vec(Vss),"csparse") P = Pf.reshape((n,K*n)) solver = Function("solver", {"a": As,"v":Vs,"p":hcat(dplesol(horzsplit(As,n),horzsplit(Vs,n),Solver,options))},dple_in(),dple_out()) refsol = Function("refsol", {"a": As,"v":Vs,"p":P},dple_in(),dple_out()) self.checkfunction(solver,refsol,inputs=inputs,failmessage=str(Solver))
def test_dple_small(self): for Solver, options in dplesolvers: for K in ([1,2,3,4] if args.run_slow else [1,2,3]): for n in [2,3]: print Solver, options numpy.random.seed(1) print (n,K) A_ = [randstable(n) for i in range(K)] V_ = [mul(v,v.T) for v in [DMatrix(numpy.random.random((n,n))) for i in range(K)]] solver = DpleSolver(Solver,dpleStruct(a=[Sparsity.dense(n,n) for i in range(K)],v=[Sparsity.dense(n,n) for i in range(K)])) solver.setOption(options) solver.init() solver.setInput(horzcat(A_),"a") solver.setInput(horzcat(V_),"v") As = MX.sym("A",n,K*n) Vs = MX.sym("V",n,K*n) def sigma(a): return a[1:] + [a[0]] def isigma(a): return [a[-1]] + a[:-1] Vss = horzcat([(i+i.T)/2 for i in isigma(list(horzsplit(Vs,n))) ]) AA = blkdiag([c.kron(i,i) for i in horzsplit(As,n)]) A_total = DMatrix.eye(n*n*K) - vertcat([AA[-n*n:,:],AA[:-n*n,:]]) Pf = solve(A_total,vec(Vss),"csparse") P = Pf.reshape((n,K*n)) refsol = MXFunction(dpleIn(a=As,v=Vs),dpleOut(p=P)) refsol.init() refsol.setInput(horzcat(A_),"a") refsol.setInput(horzcat(V_),"v") solver.evaluate() X = list(horzsplit(solver.getOutput(),n)) refsol.evaluate() Xref = list(horzsplit(refsol.getOutput(),n)) a0 = (mul([blkdiag(A_),blkdiag(X),blkdiag(A_).T])+blkdiag(V_)) a0ref = (mul([blkdiag(A_),blkdiag(Xref),blkdiag(A_).T])+blkdiag(V_)) a1 = blkdiag(sigma(X)) a1ref = blkdiag(sigma(Xref)) self.checkarray(a0ref,a1ref,failmessage=str(Solver)) self.checkarray(a0,a1,failmessage=str(Solver)) try: self.checkfunction(solver,refsol,sens_der=True,hessian=True,evals=2,failmessage=str(Solver)) except Exception as e: if "second order derivatives are not supported" in str(e): self.checkfunction(solver,refsol,evals=1,hessian=False,sens_der=False,failmessage=str(Solver)) else: raise e
def _convert(self, symbol, t, y): """ See :meth:`CasadiConverter.convert()`. """ if isinstance(symbol, (pybamm.Scalar, pybamm.Array, pybamm.Time)): return casadi.SX(symbol.evaluate(t, y)) elif isinstance(symbol, pybamm.StateVector): if y is None: raise ValueError( "Must provide a 'y' for converting state vectors") return casadi.vertcat(*[y[y_slice] for y_slice in symbol.y_slices]) elif isinstance(symbol, pybamm.BinaryOperator): left, right = symbol.children # process children converted_left = self.convert(left, t, y) converted_right = self.convert(right, t, y) if isinstance(symbol, pybamm.Outer): return casadi.kron(converted_left, converted_right) else: # _binary_evaluate defined in derived classes for specific rules return symbol._binary_evaluate(converted_left, converted_right) elif isinstance(symbol, pybamm.UnaryOperator): converted_child = self.convert(symbol.child, t, y) if isinstance(symbol, pybamm.AbsoluteValue): return casadi.fabs(converted_child) return symbol._unary_evaluate(converted_child) elif isinstance(symbol, pybamm.Function): converted_children = [ self.convert(child, t, y) for child in symbol.children ] # Special functions if symbol.function == np.min: return casadi.mmin(*converted_children) elif symbol.function == np.max: return casadi.mmax(*converted_children) elif symbol.function == np.abs: return casadi.fabs(*converted_children) elif not isinstance( symbol.function, pybamm.GetCurrent ) and symbol.function.__name__.startswith("elementwise_grad_of_"): differentiating_child_idx = int(symbol.function.__name__[-1]) # Create dummy symbolic variables in order to differentiate using CasADi dummy_vars = [ casadi.SX.sym("y_" + str(i)) for i in range(len(converted_children)) ] func_diff = casadi.gradient( symbol.differentiated_function(*dummy_vars), dummy_vars[differentiating_child_idx], ) # Create function and evaluate it using the children casadi_func_diff = casadi.Function("func_diff", dummy_vars, [func_diff]) return casadi_func_diff(*converted_children) # Other functions else: return symbol._function_evaluate(converted_children) elif isinstance(symbol, pybamm.Concatenation): converted_children = [ self.convert(child, t, y) for child in symbol.children ] if isinstance(symbol, (pybamm.NumpyConcatenation, pybamm.SparseStack)): return casadi.vertcat(*converted_children) # DomainConcatenation specifies a particular ordering for the concatenation, # which we must follow elif isinstance(symbol, pybamm.DomainConcatenation): slice_starts = [] all_child_vectors = [] for i in range(symbol.secondary_dimensions_npts): child_vectors = [] for child_var, slices in zip(converted_children, symbol._children_slices): for child_dom, child_slice in slices.items(): slice_starts.append( symbol._slices[child_dom][i].start) child_vectors.append( child_var[child_slice[i].start:child_slice[i]. stop]) all_child_vectors.extend([ v for _, v in sorted(zip(slice_starts, child_vectors)) ]) return casadi.vertcat(*all_child_vectors) else: raise TypeError(""" Cannot convert symbol of type '{}' to CasADi. Symbols must all be 'linear algebra' at this stage. """.format(type(symbol)))
def test_dple_small(self): for Solver, options in dplesolvers: for K in ([1, 2, 3, 4] if args.run_slow else [1, 2, 3]): for n in [2, 3]: print Solver, options numpy.random.seed(1) print(n, K) A_ = [randstable(n) for i in range(K)] V_ = [ mul(v, v.T) for v in [ DMatrix(numpy.random.random((n, n))) for i in range(K) ] ] solver = DpleSolver( "solver", Solver, { 'a': [Sparsity.dense(n, n) for i in range(K)], 'v': [Sparsity.dense(n, n) for i in range(K)] }, options) solver.setInput(horzcat(A_), "a") solver.setInput(horzcat(V_), "v") As = MX.sym("A", n, K * n) Vs = MX.sym("V", n, K * n) def sigma(a): return a[1:] + [a[0]] def isigma(a): return [a[-1]] + a[:-1] Vss = horzcat([(i + i.T) / 2 for i in isigma(list(horzsplit(Vs, n)))]) AA = diagcat([c.kron(i, i) for i in horzsplit(As, n)]) A_total = DMatrix.eye(n * n * K) - vertcat( [AA[-n * n:, :], AA[:-n * n, :]]) Pf = solve(A_total, vec(Vss), "csparse") P = Pf.reshape((n, K * n)) refsol = MXFunction("refsol", dpleIn(a=As, v=Vs), dpleOut(p=P)) refsol.setInput(horzcat(A_), "a") refsol.setInput(horzcat(V_), "v") solver.evaluate() X = list(horzsplit(solver.getOutput(), n)) refsol.evaluate() Xref = list(horzsplit(refsol.getOutput(), n)) a0 = (mul([diagcat(A_), diagcat(X), diagcat(A_).T]) + diagcat(V_)) a0ref = (mul([diagcat(A_), diagcat(Xref), diagcat(A_).T]) + diagcat(V_)) a1 = diagcat(sigma(X)) a1ref = diagcat(sigma(Xref)) self.checkarray(a0ref, a1ref, failmessage=str(Solver)) self.checkarray(a0, a1, failmessage=str(Solver)) try: self.checkfunction(solver, refsol, sens_der=True, hessian=True, evals=2, failmessage=str(Solver)) except Exception as e: if "second order derivatives are not supported" in str( e): self.checkfunction(solver, refsol, evals=1, hessian=False, sens_der=False, failmessage=str(Solver)) else: raise e
def test_dle_small(self): for Solver, options in dlesolvers: for n in [2, 3, 4]: numpy.random.seed(1) print(n) r = 0.8 A_ = tril(DMatrix(numpy.random.random((n, n)))) for i in range(n): A_[i, i] = numpy.random.random() * r * 2 - r Q = scipy.linalg.orth(numpy.random.random((n, n))) A_ = mul([Q, A_, Q.T]) v = DMatrix(numpy.random.random((n, n))) V_ = mul(v, v.T) solver = DleSolver("solver", Solver, { 'a': Sparsity.dense(n, n), 'v': Sparsity.dense(n, n) }, options) solver.setInput(A_, "a") solver.setInput(V_, "v") As = MX.sym("A", n, n) Vs = MX.sym("V", n, n) Vss = (Vs + Vs.T) / 2 A_total = DMatrix.eye(n * n) - c.kron(As, As) Pf = solve(A_total, vec(Vss), "csparse") refsol = MXFunction("refsol", dleIn(a=As, v=Vs), dleOut(p=Pf.reshape((n, n)))) refsol.setInput(A_, "a") refsol.setInput(V_, "v") solver.evaluate() X = solver.getOutput() refsol.evaluate() Xref = refsol.getOutput() a0 = (mul([A_, X, A_.T]) + V_) a0ref = (mul([A_, Xref, A_.T]) + V_) a1 = X a1ref = Xref self.checkarray(a0ref, a1ref) self.checkarray(a0, a1) try: self.checkfunction(solver, refsol, sens_der=True, hessian=True, evals=2, failmessage=str(Solver)) except Exception as e: if "second order derivatives are not supported" in str(e): self.checkfunction(solver, refsol, evals=1, hessian=False, sens_der=False, failmessage=str(Solver)) else: raise e
def __init__(self, dae, t, order, method='legendre', parallelization='serial', tdp_fun=None, expand=True, repeat_param=False, options={}): """Constructor @param t time vector of length N+1 defining N collocation intervals @param order number of collocation points per interval @param method collocation method ('legendre', 'radau') @param dae DAE model @param parallelization parallelization of the outer map. Possible set of values is the same as for casadi.Function.map(). @return Returns a dictionary with the following keys: 'X' -- state at collocation points 'Z' -- alg. state at collocation points 'x0' -- initial state 'eq' -- the expression eq == 0 defines the collocation equation. eq depends on X, Z, x0, p. 'Q' -- quadrature values at collocation points depending on x0, X, Z, p. """ # Convert whatever DAE to implicit DAE dae = dae.makeImplicit() M = order N = len(t) - 1 # # Define variables and functions corresponfing to all control intervals # K = cs.MX.sym('K', dae.nx, N * M) # State derivatives at collocation points Z = cs.MX.sym('Z', dae.nz, N * M) # Alg state at collocation points x = cs.MX.sym('x', dae.nx, N + 1) # State at the ends of collocation intervals (t) u = cs.MX.sym('u', dae.nu, N) # Input on collocation intervals U = cs.horzcat(*[cs.repmat(u[:, n], 1, M) for n in range(N)]) # Input at collocation points # Butcher tableau for the selected method butcher = butcherTableuForCollocationMethod(order, method) # Interval lengths h = np.diff(t) # Integrated state at collocation points Mx = cs.kron(cs.DM.eye(N), cs.DM.ones(1, M)) MK = cs.kron(cs.diagcat(*h), butcher.A.T) # integration matrix X = cs.mtimes(x[:, : -1], Mx) + cs.mtimes(K, MK) # Integrated state at the ends of collocation intervals xf = x[:, : -1] + cs.mtimes(K, cs.kron(cs.diagcat(*h), butcher.b)) # Points in time at which the collocation equations are calculated # TODO: this possibly can be sped up a little bit. tc = np.hstack([t[n] + h[n] * butcher.c for n in range(N)]) # Values of the time-dependent parameter if tdp_fun is not None: tdp_val = cs.horzcat(*[tdp_fun(t) for t in tc]) else: assert dae.ntdp == 0 tdp_val = np.zeros((0, tc.size)) # DAE function dae_fun = dae.createFunction('dae', ['xdot', 'x', 'z', 'u', 'p', 't', 'tdp'], ['dae', 'quad']) if expand: dae_fun = dae_fun.expand() # expand() for speed if repeat_param: reduce_in = [] p = cs.MX.sym('P', dae.np, N * M) else: reduce_in = [4] p = cs.MX.sym('P', dae.np) dae_map = dae_fun.map('dae_map', parallelization, N * M, reduce_in, [], options) dae_out = dae_map(xdot=K, x=X, z=Z, u=U, p=p, t=tc, tdp=tdp_val) eqc = ce.struct_MX([ ce.entry('collocation', expr=dae_out['dae']), ce.entry('continuity', expr=xf - x[:, 1 :]), ce.entry('param', expr=cs.diff(p, 1, 1)) ]) # Integrate the quadrature state quad = dae_out['quad'] #t0 = time.time() q = [cs.MX.zeros(dae.nq)] # Integrated quadrature at interval ends # TODO: speed up the calculation of q. for n in range(N): q.append(q[-1] + h[n] * cs.mtimes(quad[:, n * M : (n + 1) * M], butcher.b)) q = cs.horzcat(*q) Q = cs.mtimes(q[:, : -1], Mx) + cs.mtimes(quad, MK) # Integrated quadrature at collocation points #print('Creating Q took {0:.3f} s.'.format(time.time() - t0)) self._N = N self._M = M self._eq = eqc self._x = x self._X = X self._K = K self._Z = Z self._U = U self._u = u self._quad = quad self._Q = Q self._q = q self._p = p self._tc = tc self._butcher = butcher self._tdp = tdp_val self._t = t
def test_dple_small(self): for Solver, options in dplesolvers: for K in ([1,2,3,4] if args.run_slow else [1,2,3]): for n in [2,3]: numpy.random.seed(1) print (n,K) A_ = [DMatrix(numpy.random.random((n,n))) for i in range(K)] V_ = [mul(v,v.T) for v in [DMatrix(numpy.random.random((n,n))) for i in range(K)]] solver = Solver([Sparsity.dense(n,n) for i in range(K)],[Sparsity.dense(n,n) for i in range(K)]) solver.setOption(options) solver.init() solver.setInput(horzcat(A_),DPLE_A) solver.setInput(horzcat(V_),DPLE_V) As = MX.sym("A",n,K*n) Vs = MX.sym("V",n,K*n) def sigma(a): return a[1:] + [a[0]] def isigma(a): return [a[-1]] + a[:-1] Vss = horzcat([(i+i.T)/2 for i in isigma(list(horzsplit(Vs,n))) ]) AA = blkdiag([c.kron(i,i) for i in horzsplit(As,n)]) A_total = DMatrix.eye(n*n*K) - vertcat([AA[-n*n:,:],AA[:-n*n,:]]) Pf = solve(A_total,vec(Vss),CSparse) P = Pf.reshape((n,K*n)) refsol = MXFunction([As,Vs],[P]) refsol.init() refsol.setInput(horzcat(A_),DPLE_A) refsol.setInput(horzcat(V_),DPLE_V) solver.evaluate() X = list(horzsplit(solver.getOutput(),n)) refsol.evaluate() Xref = list(horzsplit(refsol.getOutput(),n)) a0 = (mul([blkdiag(A_),blkdiag(X),blkdiag(A_).T])+blkdiag(V_)) a0ref = (mul([blkdiag(A_),blkdiag(Xref),blkdiag(A_).T])+blkdiag(V_)) a1 = blkdiag(sigma(X)) a1ref = blkdiag(sigma(Xref)) self.checkarray(a0ref,a1ref) self.checkarray(a0,a1) self.checkfunction(solver,refsol,sens_der=False,hessian=False,evals=1)