| 2346 | |
| 2347 | |
| 2348 | |
| 2349 | ############################################# |
| 2350 | # Decorators |
| 2351 | ############################################# |
| 2352 | |
| 2353 | # Infix operator decorator |
| 2354 | from functools import wraps |
| 2355 | from copy import copy |
| 2356 | class infix_operator(object): |
| 2357 | """ |
| 2358 | A decorator for functions which allows for a hack that makes |
| 2359 | the function behave like an infix operator. |
| 2360 | |
| 2361 | This decorator exists as a convenience for interactive use. |
| 2362 | |
| 2363 | EXAMPLES: |
| 2364 | |
| 2365 | An infix dot product operator:: |
| 2366 | |
| 2367 | sage: def dot(a,b): return a.dot_product(b) |
| 2368 | sage: dot=infix_operator('multiply')(dot) |
| 2369 | sage: u=vector([1,2,3]) |
| 2370 | sage: v=vector([5,4,3]) |
| 2371 | sage: u *dot* v |
| 2372 | 22 |
| 2373 | |
| 2374 | An infix element-wise addition operator:: |
| 2375 | |
| 2376 | sage: def eadd(a,b): |
| 2377 | ... return a.parent([i+j for i,j in zip(a,b)]) |
| 2378 | sage: eadd=infix_operator('add')(eadd) |
| 2379 | sage: u=vector([1,2,3]) |
| 2380 | sage: v=vector([5,4,3]) |
| 2381 | sage: u +eadd+ v |
| 2382 | (6, 6, 6) |
| 2383 | sage: 2*u +eadd+ v |
| 2384 | (7, 8, 9) |
| 2385 | |
| 2386 | A hack to simulate a postfix operator:: |
| 2387 | |
| 2388 | sage: def thendo(a,b): return b(a) |
| 2389 | sage: thendo=infix_operator('or')(thendo) |
| 2390 | sage: x |thendo| cos |thendo| (lambda x: x^2) |
| 2391 | cos(x)^2 |
| 2392 | """ |
| 2393 | |
| 2394 | def __init__(self, precedence): |
| 2395 | """ |
| 2396 | A decorator for functions which allows for a hack that makes |
| 2397 | the function behave like an infix operator. |
| 2398 | |
| 2399 | This decorator exists as a convenience for interactive use. |
| 2400 | |
| 2401 | EXAMPLES:: |
| 2402 | |
| 2403 | sage: def dot(a,b): return a.dot_product(b) |
| 2404 | sage: dot=infix_operator('multiply')(dot) |
| 2405 | sage: u=vector([1,2,3]) |
| 2406 | sage: v=vector([5,4,3]) |
| 2407 | sage: u *dot* v |
| 2408 | 22 |
| 2409 | |
| 2410 | sage: def eadd(a,b): |
| 2411 | ... return a.parent([i+j for i,j in zip(a,b)]) |
| 2412 | sage: eadd=infix_operator('add')(eadd) |
| 2413 | sage: u=vector([1,2,3]) |
| 2414 | sage: v=vector([5,4,3]) |
| 2415 | sage: u +eadd+ v |
| 2416 | (6, 6, 6) |
| 2417 | sage: 2*u +eadd+ v |
| 2418 | (7, 8, 9) |
| 2419 | |
| 2420 | sage: def thendo(a,b): return b(a) |
| 2421 | sage: thendo=infix_operator('or')(thendo) |
| 2422 | sage: x |thendo| cos |thendo| (lambda x: x^2) |
| 2423 | cos(x)^2 |
| 2424 | """ |
| 2425 | self.precedence=precedence |
| 2426 | |
| 2427 | operators={'add': {'left': '__add__', 'right': '__radd__'}, |
| 2428 | 'multiply': {'left': '__mul__', 'right': '__rmul__'}, |
| 2429 | 'or': {'left': '__or__', 'right': '__ror__'}, |
| 2430 | } |
| 2431 | |
| 2432 | def __call__(self, func): |
| 2433 | """ |
| 2434 | Returns a function which acts as an inline operator. |
| 2435 | |
| 2436 | EXAMPLES:: |
| 2437 | |
| 2438 | sage: def dot(a,b): return a.dot_product(b) |
| 2439 | sage: dot=infix_operator('multiply')(dot) |
| 2440 | sage: u=vector([1,2,3]) |
| 2441 | sage: v=vector([5,4,3]) |
| 2442 | sage: u *dot* v |
| 2443 | 22 |
| 2444 | |
| 2445 | sage: def eadd(a,b): |
| 2446 | ... return a.parent([i+j for i,j in zip(a,b)]) |
| 2447 | sage: eadd=infix_operator('add')(eadd) |
| 2448 | sage: u=vector([1,2,3]) |
| 2449 | sage: v=vector([5,4,3]) |
| 2450 | sage: u +eadd+ v |
| 2451 | (6, 6, 6) |
| 2452 | sage: 2*u +eadd+ v |
| 2453 | (7, 8, 9) |
| 2454 | |
| 2455 | sage: def thendo(a,b): return b(a) |
| 2456 | sage: thendo=infix_operator('or')(thendo) |
| 2457 | sage: x |thendo| cos |thendo| (lambda x: x^2) |
| 2458 | cos(x)^2 |
| 2459 | """ |
| 2460 | def left_func(self, right): |
| 2461 | """ |
| 2462 | The function for the operation on the left (e.g., __add__). |
| 2463 | |
| 2464 | EXAMPLES:: |
| 2465 | |
| 2466 | sage: def dot(a,b): return a.dot_product(b) |
| 2467 | sage: dot=infix_operator('multiply')(dot) |
| 2468 | sage: u=vector([1,2,3]) |
| 2469 | sage: v=vector([5,4,3]) |
| 2470 | sage: u *dot* v |
| 2471 | 22 |
| 2472 | """ |
| 2473 | |
| 2474 | if self.left is None: |
| 2475 | if self.right is None: |
| 2476 | new = copy(self) |
| 2477 | new.right=right |
| 2478 | return new |
| 2479 | else: |
| 2480 | raise SyntaxError, "Infix operator already has its right argument" |
| 2481 | else: |
| 2482 | return self.function(self.left, right) |
| 2483 | |
| 2484 | def right_func(self, left): |
| 2485 | """ |
| 2486 | The function for the operation on the right (e.g., __radd__). |
| 2487 | |
| 2488 | EXAMPLES:: |
| 2489 | |
| 2490 | sage: def dot(a,b): return a.dot_product(b) |
| 2491 | sage: dot=infix_operator('multiply')(dot) |
| 2492 | sage: u=vector([1,2,3]) |
| 2493 | sage: v=vector([5,4,3]) |
| 2494 | sage: u *dot* v |
| 2495 | 22 |
| 2496 | """ |
| 2497 | if self.right is None: |
| 2498 | if self.left is None: |
| 2499 | new = copy(self) |
| 2500 | new.left=left |
| 2501 | return new |
| 2502 | else: |
| 2503 | raise SyntaxError, "Infix operator already has its left argument" |
| 2504 | else: |
| 2505 | return self.function(left, self.right) |
| 2506 | |
| 2507 | |
| 2508 | @wraps(func) |
| 2509 | class wrapper: |
| 2510 | def __init__(self, left=None, right=None): |
| 2511 | """ |
| 2512 | Initialize the actual infix object, with possibly a |
| 2513 | specified left and/or right operand. |
| 2514 | |
| 2515 | EXAMPLES:: |
| 2516 | |
| 2517 | sage: def dot(a,b): return a.dot_product(b) |
| 2518 | sage: dot=infix_operator('multiply')(dot) |
| 2519 | sage: u=vector([1,2,3]) |
| 2520 | sage: v=vector([5,4,3]) |
| 2521 | sage: u *dot* v |
| 2522 | 22 |
| 2523 | """ |
| 2524 | |
| 2525 | self.function = func |
| 2526 | self.left = left |
| 2527 | self.right = right |
| 2528 | def __call__(self, *args, **kwds): |
| 2529 | """ |
| 2530 | Call the passed function. |
| 2531 | |
| 2532 | EXAMPLES:: |
| 2533 | |
| 2534 | sage: def dot(a,b): return a.dot_product(b) |
| 2535 | sage: dot=infix_operator('multiply')(dot) |
| 2536 | sage: u=vector([1,2,3]) |
| 2537 | sage: v=vector([5,4,3]) |
| 2538 | sage: dot(u,v) |
| 2539 | 22 |
| 2540 | """ |
| 2541 | return self.function(*args, **kwds) |
| 2542 | |
| 2543 | setattr(wrapper, self.operators[self.precedence]['left'], left_func) |
| 2544 | setattr(wrapper, self.operators[self.precedence]['right'], right_func) |
| 2545 | |
| 2546 | from sage.misc.sageinspect import sage_getsource |
| 2547 | wrapper._sage_src_ = lambda: sage_getsource(func) |
| 2548 | |
| 2549 | return wrapper() |