Ticket #6245: trac-6245-infix-decorator.patch

File trac-6245-infix-decorator.patch, 7.5 KB (added by jason, 11 years ago)

rebased

  • sage/misc/all.py

    # HG changeset patch
    # User Jason Grout <jason-sage@creativetrax.com>
    # Date 1253173276 18000
    # Node ID a9dcc6420d6ea0c3d71776b52ab5c3fd6a32d25c
    # Parent  d92d4d494922f0e3db8aece7972365133003d908
    Make a decorator for making new infix operators.
    
    diff -r d92d4d494922 -r a9dcc6420d6e sage/misc/all.py
    a b  
    77                  repr_lincomb, tmp_dir, tmp_filename,
    88                  pad_zeros, attrcall,
    99                  DOT_SAGE, SAGE_ROOT, SAGE_URL, SAGE_DB, SAGE_TMP,
    10                   is_32_bit, is_64_bit, newton_method_sizes)
     10                  is_32_bit, is_64_bit, newton_method_sizes, infix_operator)
    1111
    1212from misc_c import prod, running_total, balanced_sum
    1313
  • sage/misc/misc.py

    diff -r d92d4d494922 -r a9dcc6420d6e sage/misc/misc.py
    a b  
    23432343        inject_variable(name, value)
    23442344    else:
    23452345        inject_variable_test(name, value, depth - 1)
     2346
     2347
     2348
     2349#############################################
     2350# Decorators
     2351#############################################
     2352
     2353# Infix operator decorator
     2354from functools import wraps
     2355from copy import copy
     2356class 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()