Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/numexpr/necompiler.py: 15%

465 statements  

« prev     ^ index     » next       coverage.py v7.2.5, created at 2023-05-10 06:15 +0000

1################################################################### 

2# Numexpr - Fast numerical array expression evaluator for NumPy. 

3# 

4# License: MIT 

5# Author: See AUTHORS.txt 

6# 

7# See LICENSE.txt and LICENSES/*.txt for details about copyright and 

8# rights to use. 

9#################################################################### 

10 

11import __future__ 

12import sys 

13import numpy 

14import threading 

15 

16is_cpu_amd_intel = False # DEPRECATION WARNING: WILL BE REMOVED IN FUTURE RELEASE 

17from numexpr import interpreter, expressions, use_vml 

18from numexpr.utils import CacheDict 

19 

20# Declare a double type that does not exist in Python space 

21double = numpy.double 

22double = numpy.double 

23 

24int_ = numpy.int32 

25long_ = numpy.int64 

26 

27typecode_to_kind = {'b': 'bool', 'i': 'int', 'l': 'long', 'f': 'float', 'd': 'double', 

28 'c': 'complex', 'n': 'none', 's': 'str'} 

29kind_to_typecode = {'bool': 'b', 'int': 'i', 'long': 'l', 'float': 'f', 'double': 'd', 

30 'complex': 'c', 'bytes': 's', 'str': 's', 'none': 'n'} 

31type_to_typecode = {bool: 'b', int_: 'i', long_: 'l', float: 'f', 

32 double: 'd', complex: 'c', bytes: 's', str: 's'} 

33type_to_kind = expressions.type_to_kind 

34kind_to_type = expressions.kind_to_type 

35default_type = kind_to_type[expressions.default_kind] 

36scalar_constant_kinds = list(kind_to_typecode.keys()) 

37 

38# VML functions that are implemented in numexpr 

39vml_functions = [ 

40 "div", # interp_body.cpp 

41 "inv", # interp_body.cpp 

42 "pow", # interp_body.cpp 

43 # Keep the rest of this list in sync with the ones listed in functions.hpp 

44 "sqrt", 

45 "sin", 

46 "cos", 

47 "tan", 

48 "arcsin", 

49 "arccos", 

50 "arctan", 

51 "sinh", 

52 "cosh", 

53 "tanh", 

54 "arcsinh", 

55 "arccosh", 

56 "arctanh", 

57 "log", 

58 "log1p", 

59 "log10", 

60 "exp", 

61 "expm1", 

62 "absolute", 

63 "conjugate", 

64 "arctan2", 

65 "fmod", 

66 "ceil", 

67 "floor" 

68 ] 

69 

70 

71class ASTNode(object): 

72 """Abstract Syntax Tree node. 

73 

74 Members: 

75 

76 astType -- type of node (op, constant, variable, raw, or alias) 

77 astKind -- the type of the result (bool, float, etc.) 

78 value -- value associated with this node. 

79 An opcode, numerical value, a variable name, etc. 

80 children -- the children below this node 

81 reg -- the register assigned to the result for this node. 

82 """ 

83 cmpnames = ['astType', 'astKind', 'value', 'children'] 

84 

85 def __init__(self, astType='generic', astKind='unknown', value=None, children=()): 

86 object.__init__(self) 

87 self.astType = astType 

88 self.astKind = astKind 

89 self.value = value 

90 self.children = tuple(children) 

91 self.reg = None 

92 

93 def __eq__(self, other): 

94 if self.astType == 'alias': 

95 self = self.value 

96 if other.astType == 'alias': 

97 other = other.value 

98 if not isinstance(other, ASTNode): 

99 return False 

100 for name in self.cmpnames: 

101 if getattr(self, name) != getattr(other, name): 

102 return False 

103 return True 

104 

105 def __lt__(self,other): 

106 # RAM: this is a fix for issue #88 whereby sorting on constants  

107 # that may be of astKind == 'complex' but type(self.value) == int or float 

108 # Here we let NumPy sort as it will cast data properly for comparison  

109 # when the Python built-ins will raise an error. 

110 if self.astType == 'constant': 

111 if self.astKind == other.astKind: 

112 return numpy.array(self.value) < numpy.array(other.value) 

113 return self.astKind < other.astKind 

114 else: 

115 raise TypeError('Sorting not implemented for astType: %s'%self.astType) 

116 

117 def __hash__(self): 

118 if self.astType == 'alias': 

119 self = self.value 

120 return hash((self.astType, self.astKind, self.value, self.children)) 

121 

122 def __str__(self): 

123 return 'AST(%s, %s, %s, %s, %s)' % (self.astType, self.astKind, 

124 self.value, self.children, self.reg) 

125 

126 def __repr__(self): 

127 return '<AST object at %s>' % id(self) 

128 

129 def key(self): 

130 return (self.astType, self.astKind, self.value, self.children) 

131 

132 def typecode(self): 

133 return kind_to_typecode[self.astKind] 

134 

135 def postorderWalk(self): 

136 for c in self.children: 

137 for w in c.postorderWalk(): 

138 yield w 

139 yield self 

140 

141 def allOf(self, *astTypes): 

142 astTypes = set(astTypes) 

143 for w in self.postorderWalk(): 

144 if w.astType in astTypes: 

145 yield w 

146 

147 

148def expressionToAST(ex): 

149 """Take an expression tree made out of expressions.ExpressionNode, 

150 and convert to an AST tree. 

151 

152 This is necessary as ExpressionNode overrides many methods to act 

153 like a number. 

154 """ 

155 return ASTNode(ex.astType, ex.astKind, ex.value, 

156 [expressionToAST(c) for c in ex.children]) 

157 

158 

159def sigPerms(s): 

160 """Generate all possible signatures derived by upcasting the given 

161 signature. 

162 """ 

163 codes = 'bilfdc' 

164 if not s: 

165 yield '' 

166 elif s[0] in codes: 

167 start = codes.index(s[0]) 

168 for x in codes[start:]: 

169 for y in sigPerms(s[1:]): 

170 yield x + y 

171 elif s[0] == 's': # numbers shall not be cast to strings 

172 for y in sigPerms(s[1:]): 

173 yield 's' + y 

174 else: 

175 yield s 

176 

177 

178def typeCompileAst(ast): 

179 """Assign appropriate types to each node in the AST. 

180 

181 Will convert opcodes and functions to appropriate upcast version, 

182 and add "cast" ops if needed. 

183 """ 

184 children = list(ast.children) 

185 if ast.astType == 'op': 

186 retsig = ast.typecode() 

187 basesig = ''.join(x.typecode() for x in list(ast.children)) 

188 # Find some operation that will work on an acceptable casting of args. 

189 for sig in sigPerms(basesig): 

190 value = (ast.value + '_' + retsig + sig).encode('ascii') 

191 if value in interpreter.opcodes: 

192 break 

193 else: 

194 for sig in sigPerms(basesig): 

195 funcname = (ast.value + '_' + retsig + sig).encode('ascii') 

196 if funcname in interpreter.funccodes: 

197 value = ('func_%sn' % (retsig + sig)).encode('ascii') 

198 children += [ASTNode('raw', 'none', 

199 interpreter.funccodes[funcname])] 

200 break 

201 else: 

202 raise NotImplementedError( 

203 "couldn't find matching opcode for '%s'" 

204 % (ast.value + '_' + retsig + basesig)) 

205 # First just cast constants, then cast variables if necessary: 

206 for i, (have, want) in enumerate(zip(basesig, sig)): 

207 if have != want: 

208 kind = typecode_to_kind[want] 

209 if children[i].astType == 'constant': 

210 children[i] = ASTNode('constant', kind, children[i].value) 

211 else: 

212 opname = "cast" 

213 children[i] = ASTNode('op', kind, opname, [children[i]]) 

214 else: 

215 value = ast.value 

216 children = ast.children 

217 return ASTNode(ast.astType, ast.astKind, value, 

218 [typeCompileAst(c) for c in children]) 

219 

220 

221class Register(object): 

222 """Abstraction for a register in the VM. 

223 

224 Members: 

225 node -- the AST node this corresponds to 

226 temporary -- True if this isn't an input or output 

227 immediate -- not a register, but an immediate value 

228 n -- the physical register number. 

229 None if no number assigned yet. 

230 """ 

231 

232 def __init__(self, astnode, temporary=False): 

233 self.node = astnode 

234 self.temporary = temporary 

235 self.immediate = False 

236 self.n = None 

237 

238 def __str__(self): 

239 if self.temporary: 

240 name = 'Temporary' 

241 else: 

242 name = 'Register' 

243 return '%s(%s, %s, %s)' % (name, self.node.astType, 

244 self.node.astKind, self.n,) 

245 

246 def __repr__(self): 

247 return self.__str__() 

248 

249 

250class Immediate(Register): 

251 """Representation of an immediate (integer) operand, instead of 

252 a register. 

253 """ 

254 

255 def __init__(self, astnode): 

256 Register.__init__(self, astnode) 

257 self.immediate = True 

258 

259 def __str__(self): 

260 return 'Immediate(%d)' % (self.node.value,) 

261 

262 

263def stringToExpression(s, types, context): 

264 """Given a string, convert it to a tree of ExpressionNode's. 

265 """ 

266 old_ctx = expressions._context.get_current_context() 

267 try: 

268 expressions._context.set_new_context(context) 

269 # first compile to a code object to determine the names 

270 if context.get('truediv', False): 

271 flags = __future__.division.compiler_flag 

272 else: 

273 flags = 0 

274 c = compile(s, '<expr>', 'eval', flags) 

275 # make VariableNode's for the names 

276 names = {} 

277 for name in c.co_names: 

278 if name == "None": 

279 names[name] = None 

280 elif name == "True": 

281 names[name] = True 

282 elif name == "False": 

283 names[name] = False 

284 else: 

285 t = types.get(name, default_type) 

286 names[name] = expressions.VariableNode(name, type_to_kind[t]) 

287 names.update(expressions.functions) 

288 # now build the expression 

289 ex = eval(c, names) 

290 if expressions.isConstant(ex): 

291 ex = expressions.ConstantNode(ex, expressions.getKind(ex)) 

292 elif not isinstance(ex, expressions.ExpressionNode): 

293 raise TypeError("unsupported expression type: %s" % type(ex)) 

294 finally: 

295 expressions._context.set_new_context(old_ctx) 

296 return ex 

297 

298 

299def isReduction(ast): 

300 prefixes = (b'sum_', b'prod_', b'min_', b'max_') 

301 return any(ast.value.startswith(p) for p in prefixes) 

302 

303 

304def getInputOrder(ast, input_order=None): 

305 """ 

306 Derive the input order of the variables in an expression. 

307 """ 

308 variables = {} 

309 for a in ast.allOf('variable'): 

310 variables[a.value] = a 

311 variable_names = set(variables.keys()) 

312 

313 if input_order: 

314 if variable_names != set(input_order): 

315 raise ValueError( 

316 "input names (%s) don't match those found in expression (%s)" 

317 % (input_order, variable_names)) 

318 

319 ordered_names = input_order 

320 else: 

321 ordered_names = list(variable_names) 

322 ordered_names.sort() 

323 ordered_variables = [variables[v] for v in ordered_names] 

324 return ordered_variables 

325 

326 

327def convertConstantToKind(x, kind): 

328 # Exception for 'float' types that will return the NumPy float32 type 

329 if kind == 'float': 

330 return numpy.float32(x) 

331 elif isinstance(x,str): 

332 return x.encode('ascii') 

333 return kind_to_type[kind](x) 

334 

335 

336def getConstants(ast): 

337 """ 

338 RAM: implemented magic method __lt__ for ASTNode to fix issues 

339 #88 and #209. The following test code works now, as does the test suite. 

340 

341 import numexpr as ne 

342 a = 1 + 3j; b = 5.0 

343 ne.evaluate('a*2 + 15j - b') 

344 """ 

345 constant_registers = set([node.reg for node in ast.allOf("constant")]) 

346 constants_order = sorted([r.node for r in constant_registers]) 

347 constants = [convertConstantToKind(a.value, a.astKind) 

348 for a in constants_order] 

349 return constants_order, constants 

350 

351 

352def sortNodesByOrder(nodes, order): 

353 order_map = {} 

354 for i, (_, v, _) in enumerate(order): 

355 order_map[v] = i 

356 dec_nodes = [(order_map[n.value], n) for n in nodes] 

357 dec_nodes.sort() 

358 return [a[1] for a in dec_nodes] 

359 

360 

361def assignLeafRegisters(inodes, registerMaker): 

362 """ 

363 Assign new registers to each of the leaf nodes. 

364 """ 

365 leafRegisters = {} 

366 for node in inodes: 

367 key = node.key() 

368 if key in leafRegisters: 

369 node.reg = leafRegisters[key] 

370 else: 

371 node.reg = leafRegisters[key] = registerMaker(node) 

372 

373 

374def assignBranchRegisters(inodes, registerMaker): 

375 """ 

376 Assign temporary registers to each of the branch nodes. 

377 """ 

378 for node in inodes: 

379 node.reg = registerMaker(node, temporary=True) 

380 

381 

382def collapseDuplicateSubtrees(ast): 

383 """ 

384 Common subexpression elimination. 

385 """ 

386 seen = {} 

387 aliases = [] 

388 for a in ast.allOf('op'): 

389 if a in seen: 

390 target = seen[a] 

391 a.astType = 'alias' 

392 a.value = target 

393 a.children = () 

394 aliases.append(a) 

395 else: 

396 seen[a] = a 

397 # Set values and registers so optimizeTemporariesAllocation 

398 # doesn't get confused 

399 for a in aliases: 

400 while a.value.astType == 'alias': 

401 a.value = a.value.value 

402 return aliases 

403 

404 

405def optimizeTemporariesAllocation(ast): 

406 """ 

407 Attempt to minimize the number of temporaries needed, by reusing old ones. 

408 """ 

409 nodes = [n for n in ast.postorderWalk() if n.reg.temporary] 

410 users_of = dict((n.reg, set()) for n in nodes) 

411 

412 node_regs = dict((n, set(c.reg for c in n.children if c.reg.temporary)) 

413 for n in nodes) 

414 if nodes and nodes[-1] is not ast: 

415 nodes_to_check = nodes + [ast] 

416 else: 

417 nodes_to_check = nodes 

418 for n in nodes_to_check: 

419 for c in n.children: 

420 if c.reg.temporary: 

421 users_of[c.reg].add(n) 

422 

423 unused = dict([(tc, set()) for tc in scalar_constant_kinds]) 

424 for n in nodes: 

425 for c in n.children: 

426 reg = c.reg 

427 if reg.temporary: 

428 users = users_of[reg] 

429 users.discard(n) 

430 if not users: 

431 unused[reg.node.astKind].add(reg) 

432 if unused[n.astKind]: 

433 reg = unused[n.astKind].pop() 

434 users_of[reg] = users_of[n.reg] 

435 n.reg = reg 

436 

437 

438def setOrderedRegisterNumbers(order, start): 

439 """ 

440 Given an order of nodes, assign register numbers. 

441 """ 

442 for i, node in enumerate(order): 

443 node.reg.n = start + i 

444 return start + len(order) 

445 

446 

447def setRegisterNumbersForTemporaries(ast, start): 

448 """ 

449 Assign register numbers for temporary registers, keeping track of 

450 aliases and handling immediate operands. 

451 """ 

452 seen = 0 

453 signature = '' 

454 aliases = [] 

455 for node in ast.postorderWalk(): 

456 if node.astType == 'alias': 

457 aliases.append(node) 

458 node = node.value 

459 if node.reg.immediate: 

460 node.reg.n = node.value 

461 continue 

462 reg = node.reg 

463 if reg.n is None: 

464 reg.n = start + seen 

465 seen += 1 

466 signature += reg.node.typecode() 

467 for node in aliases: 

468 node.reg = node.value.reg 

469 return start + seen, signature 

470 

471 

472def convertASTtoThreeAddrForm(ast): 

473 """ 

474 Convert an AST to a three address form. 

475 

476 Three address form is (op, reg1, reg2, reg3), where reg1 is the 

477 destination of the result of the instruction. 

478 

479 I suppose this should be called three register form, but three 

480 address form is found in compiler theory. 

481 """ 

482 return [(node.value, node.reg) + tuple([c.reg for c in node.children]) 

483 for node in ast.allOf('op')] 

484 

485 

486def compileThreeAddrForm(program): 

487 """ 

488 Given a three address form of the program, compile it a string that 

489 the VM understands. 

490 """ 

491 

492 def nToChr(reg): 

493 if reg is None: 

494 return b'\xff' 

495 elif reg.n < 0: 

496 raise ValueError("negative value for register number %s" % reg.n) 

497 else: 

498 return bytes([reg.n]) 

499 

500 def quadrupleToString(opcode, store, a1=None, a2=None): 

501 cop = chr(interpreter.opcodes[opcode]).encode('ascii') 

502 cs = nToChr(store) 

503 ca1 = nToChr(a1) 

504 ca2 = nToChr(a2) 

505 return cop + cs + ca1 + ca2 

506 

507 def toString(args): 

508 while len(args) < 4: 

509 args += (None,) 

510 opcode, store, a1, a2 = args[:4] 

511 s = quadrupleToString(opcode, store, a1, a2) 

512 l = [s] 

513 args = args[4:] 

514 while args: 

515 s = quadrupleToString(b'noop', *args[:3]) 

516 l.append(s) 

517 args = args[3:] 

518 return b''.join(l) 

519 

520 prog_str = b''.join([toString(t) for t in program]) 

521 return prog_str 

522 

523 

524context_info = [ 

525 ('optimization', ('none', 'moderate', 'aggressive'), 'aggressive'), 

526 ('truediv', (False, True, 'auto'), 'auto') 

527] 

528 

529 

530def getContext(kwargs, frame_depth=1): 

531 d = kwargs.copy() 

532 context = {} 

533 for name, allowed, default in context_info: 

534 value = d.pop(name, default) 

535 if value in allowed: 

536 context[name] = value 

537 else: 

538 raise ValueError("'%s' must be one of %s" % (name, allowed)) 

539 

540 if d: 

541 raise ValueError("Unknown keyword argument '%s'" % d.popitem()[0]) 

542 if context['truediv'] == 'auto': 

543 caller_globals = sys._getframe(frame_depth + 1).f_globals 

544 context['truediv'] = caller_globals.get('division', None) == __future__.division 

545 

546 return context 

547 

548 

549def precompile(ex, signature=(), context={}): 

550 """ 

551 Compile the expression to an intermediate form. 

552 """ 

553 types = dict(signature) 

554 input_order = [name for (name, type_) in signature] 

555 

556 if isinstance(ex, str): 

557 ex = stringToExpression(ex, types, context) 

558 

559 # the AST is like the expression, but the node objects don't have 

560 # any odd interpretations 

561 

562 ast = expressionToAST(ex) 

563 

564 if ex.astType != 'op': 

565 ast = ASTNode('op', value='copy', astKind=ex.astKind, children=(ast,)) 

566 

567 ast = typeCompileAst(ast) 

568 

569 aliases = collapseDuplicateSubtrees(ast) 

570 

571 assignLeafRegisters(ast.allOf('raw'), Immediate) 

572 assignLeafRegisters(ast.allOf('variable', 'constant'), Register) 

573 assignBranchRegisters(ast.allOf('op'), Register) 

574 

575 # assign registers for aliases 

576 for a in aliases: 

577 a.reg = a.value.reg 

578 

579 input_order = getInputOrder(ast, input_order) 

580 constants_order, constants = getConstants(ast) 

581 

582 if isReduction(ast): 

583 ast.reg.temporary = False 

584 

585 optimizeTemporariesAllocation(ast) 

586 

587 ast.reg.temporary = False 

588 r_output = 0 

589 ast.reg.n = 0 

590 

591 r_inputs = r_output + 1 

592 r_constants = setOrderedRegisterNumbers(input_order, r_inputs) 

593 r_temps = setOrderedRegisterNumbers(constants_order, r_constants) 

594 r_end, tempsig = setRegisterNumbersForTemporaries(ast, r_temps) 

595 

596 threeAddrProgram = convertASTtoThreeAddrForm(ast) 

597 input_names = tuple([a.value for a in input_order]) 

598 signature = ''.join(type_to_typecode[types.get(x, default_type)] 

599 for x in input_names) 

600 return threeAddrProgram, signature, tempsig, constants, input_names 

601 

602 

603def NumExpr(ex, signature=(), **kwargs): 

604 """ 

605 Compile an expression built using E.<variable> variables to a function. 

606 

607 ex can also be specified as a string "2*a+3*b". 

608 

609 The order of the input variables and their types can be specified using the 

610 signature parameter, which is a list of (name, type) pairs. 

611 

612 Returns a `NumExpr` object containing the compiled function. 

613 """ 

614 # NumExpr can be called either directly by the end-user, in which case 

615 # kwargs need to be sanitized by getContext, or by evaluate, 

616 # in which case kwargs are in already sanitized. 

617 # In that case frame_depth is wrong (it should be 2) but it doesn't matter 

618 # since it will not be used (because truediv='auto' has already been 

619 # translated to either True or False). 

620 

621 context = getContext(kwargs, frame_depth=1) 

622 threeAddrProgram, inputsig, tempsig, constants, input_names = precompile(ex, signature, context) 

623 program = compileThreeAddrForm(threeAddrProgram) 

624 return interpreter.NumExpr(inputsig.encode('ascii'), 

625 tempsig.encode('ascii'), 

626 program, constants, input_names) 

627 

628 

629def disassemble(nex): 

630 """ 

631 Given a NumExpr object, return a list which is the program disassembled. 

632 """ 

633 rev_opcodes = {} 

634 for op in interpreter.opcodes: 

635 rev_opcodes[interpreter.opcodes[op]] = op 

636 r_constants = 1 + len(nex.signature) 

637 r_temps = r_constants + len(nex.constants) 

638 

639 def parseOp(op): 

640 name, sig = [*op.rsplit(b'_', 1), ''][:2] 

641 return name, sig 

642 

643 def getArg(pc, offset): 

644 arg = nex.program[pc + (offset if offset < 4 else offset+1)] 

645 _, sig = parseOp(rev_opcodes.get(nex.program[pc])) 

646 try: 

647 code = sig[offset - 1] 

648 except IndexError: 

649 return None 

650 

651 code = bytes([code]) 

652 

653 if arg == 255: 

654 return None 

655 if code != b'n': 

656 if arg == 0: 

657 return b'r0' 

658 elif arg < r_constants: 

659 return ('r%d[%s]' % (arg, nex.input_names[arg - 1])).encode('ascii') 

660 elif arg < r_temps: 

661 return ('c%d[%s]' % (arg, nex.constants[arg - r_constants])).encode('ascii') 

662 else: 

663 return ('t%d' % (arg,)).encode('ascii') 

664 else: 

665 return arg 

666 

667 source = [] 

668 for pc in range(0, len(nex.program), 4): 

669 op = rev_opcodes.get(nex.program[pc]) 

670 _, sig = parseOp(op) 

671 parsed = [op] 

672 for i in range(len(sig)): 

673 parsed.append(getArg(pc, 1 + i)) 

674 while len(parsed) < 4: 

675 parsed.append(None) 

676 source.append(parsed) 

677 return source 

678 

679 

680def getType(a): 

681 kind = a.dtype.kind 

682 if kind == 'b': 

683 return bool 

684 if kind in 'iu': 

685 if a.dtype.itemsize > 4: 

686 return long_ # ``long`` is for integers of more than 32 bits 

687 if kind == 'u' and a.dtype.itemsize == 4: 

688 return long_ # use ``long`` here as an ``int`` is not enough 

689 return int_ 

690 if kind == 'f': 

691 if a.dtype.itemsize > 4: 

692 return double # ``double`` is for floats of more than 32 bits 

693 return float 

694 if kind == 'c': 

695 return complex 

696 if kind == 'S': 

697 return bytes 

698 if kind == 'U': 

699 raise ValueError('NumExpr 2 does not support Unicode as a dtype.') 

700 raise ValueError("unknown type %s" % a.dtype.name) 

701 

702 

703def getExprNames(text, context): 

704 ex = stringToExpression(text, {}, context) 

705 ast = expressionToAST(ex) 

706 input_order = getInputOrder(ast, None) 

707 #try to figure out if vml operations are used by expression 

708 if not use_vml: 

709 ex_uses_vml = False 

710 else: 

711 for node in ast.postorderWalk(): 

712 if node.astType == 'op' and node.value in vml_functions: 

713 ex_uses_vml = True 

714 break 

715 else: 

716 ex_uses_vml = False 

717 

718 return [a.value for a in input_order], ex_uses_vml 

719 

720 

721def getArguments(names, local_dict=None, global_dict=None): 

722 """ 

723 Get the arguments based on the names. 

724 """ 

725 call_frame = sys._getframe(2) 

726 

727 clear_local_dict = False 

728 if local_dict is None: 

729 local_dict = call_frame.f_locals 

730 clear_local_dict = True 

731 try: 

732 frame_globals = call_frame.f_globals 

733 if global_dict is None: 

734 global_dict = frame_globals 

735 

736 # If `call_frame` is the top frame of the interpreter we can't clear its  

737 # `local_dict`, because it is actually the `global_dict`. 

738 clear_local_dict = clear_local_dict and not frame_globals is local_dict 

739 

740 arguments = [] 

741 for name in names: 

742 try: 

743 a = local_dict[name] 

744 except KeyError: 

745 a = global_dict[name] 

746 arguments.append(numpy.asarray(a)) 

747 finally: 

748 # If we generated local_dict via an explicit reference to f_locals, 

749 # clear the dict to prevent creating extra ref counts in the caller's scope 

750 # See https://github.com/pydata/numexpr/issues/310 

751 if clear_local_dict: 

752 local_dict.clear() 

753 

754 return arguments 

755 

756 

757# Dictionaries for caching variable names and compiled expressions 

758_names_cache = CacheDict(256) 

759_numexpr_cache = CacheDict(256) 

760_numexpr_last = {} 

761 

762evaluate_lock = threading.Lock() 

763 

764def evaluate(ex, local_dict=None, global_dict=None, 

765 out=None, order='K', casting='safe', **kwargs): 

766 """ 

767 Evaluate a simple array expression element-wise, using the new iterator. 

768 

769 ex is a string forming an expression, like "2*a+3*b". The values for "a" 

770 and "b" will by default be taken from the calling function's frame 

771 (through use of sys._getframe()). Alternatively, they can be specifed 

772 using the 'local_dict' or 'global_dict' arguments. 

773 

774 Parameters 

775 ---------- 

776 

777 local_dict : dictionary, optional 

778 A dictionary that replaces the local operands in current frame. 

779 

780 global_dict : dictionary, optional 

781 A dictionary that replaces the global operands in current frame. 

782 

783 out : NumPy array, optional 

784 An existing array where the outcome is going to be stored. Care is 

785 required so that this array has the same shape and type than the 

786 actual outcome of the computation. Useful for avoiding unnecessary 

787 new array allocations. 

788 

789 order : {'C', 'F', 'A', or 'K'}, optional 

790 Controls the iteration order for operands. 'C' means C order, 'F' 

791 means Fortran order, 'A' means 'F' order if all the arrays are 

792 Fortran contiguous, 'C' order otherwise, and 'K' means as close to 

793 the order the array elements appear in memory as possible. For 

794 efficient computations, typically 'K'eep order (the default) is 

795 desired. 

796 

797 casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional 

798 Controls what kind of data casting may occur when making a copy or 

799 buffering. Setting this to 'unsafe' is not recommended, as it can 

800 adversely affect accumulations. 

801 

802 * 'no' means the data types should not be cast at all. 

803 * 'equiv' means only byte-order changes are allowed. 

804 * 'safe' means only casts which can preserve values are allowed. 

805 * 'same_kind' means only safe casts or casts within a kind, 

806 like float64 to float32, are allowed. 

807 * 'unsafe' means any data conversions may be done. 

808 """ 

809 global _numexpr_last 

810 if not isinstance(ex, str): 

811 raise ValueError("must specify expression as a string") 

812 

813 # Get the names for this expression 

814 context = getContext(kwargs, frame_depth=1) 

815 expr_key = (ex, tuple(sorted(context.items()))) 

816 if expr_key not in _names_cache: 

817 _names_cache[expr_key] = getExprNames(ex, context) 

818 names, ex_uses_vml = _names_cache[expr_key] 

819 arguments = getArguments(names, local_dict, global_dict) 

820 

821 # Create a signature 

822 signature = [(name, getType(arg)) for (name, arg) in 

823 zip(names, arguments)] 

824 

825 # Look up numexpr if possible. 

826 numexpr_key = expr_key + (tuple(signature),) 

827 try: 

828 compiled_ex = _numexpr_cache[numexpr_key] 

829 except KeyError: 

830 compiled_ex = _numexpr_cache[numexpr_key] = NumExpr(ex, signature, **context) 

831 kwargs = {'out': out, 'order': order, 'casting': casting, 

832 'ex_uses_vml': ex_uses_vml} 

833 _numexpr_last = dict(ex=compiled_ex, argnames=names, kwargs=kwargs) 

834 with evaluate_lock: 

835 return compiled_ex(*arguments, **kwargs) 

836 

837 

838def re_evaluate(local_dict=None): 

839 """ 

840 Re-evaluate the previous executed array expression without any check. 

841 

842 This is meant for accelerating loops that are re-evaluating the same 

843 expression repeatedly without changing anything else than the operands. 

844 If unsure, use evaluate() which is safer. 

845 

846 Parameters 

847 ---------- 

848 

849 local_dict : dictionary, optional 

850 A dictionary that replaces the local operands in current frame. 

851 

852 """ 

853 try: 

854 compiled_ex = _numexpr_last['ex'] 

855 except KeyError: 

856 raise RuntimeError("not a previous evaluate() execution found") 

857 argnames = _numexpr_last['argnames'] 

858 args = getArguments(argnames, local_dict) 

859 kwargs = _numexpr_last['kwargs'] 

860 with evaluate_lock: 

861 return compiled_ex(*args, **kwargs)