In pure functional languages, is there an algorithm to get the inverse function?

前端 未结 10 1215
野的像风
野的像风 2020-12-04 06:10

In pure functional languages like Haskell, is there an algorithm to get the inverse of a function, (edit) when it is bijective? And is there a specific way to program your f

相关标签:
10条回答
  • 2020-12-04 06:37

    No, it's not possible in general.

    Proof: consider bijective functions of type

    type F = [Bit] -> [Bit]
    

    with

    data Bit = B0 | B1
    

    Assume we have an inverter inv :: F -> F such that inv f . f ≡ id. Say we have tested it for the function f = id, by confirming that

    inv f (repeat B0) -> (B0 : ls)
    

    Since this first B0 in the output must have come after some finite time, we have an upper bound n on both the depth to which inv had actually evaluated our test input to obtain this result, as well as the number of times it can have called f. Define now a family of functions

    g j (B1 : B0 : ... (n+j times) ... B0 : ls)
       = B0 : ... (n+j times) ... B0 : B1 : ls
    g j (B0 : ... (n+j times) ... B0 : B1 : ls)
       = B1 : B0 : ... (n+j times) ... B0 : ls
    g j l = l
    

    Clearly, for all 0<j≤n, g j is a bijection, in fact self-inverse. So we should be able to confirm

    inv (g j) (replicate (n+j) B0 ++ B1 : repeat B0) -> (B1 : ls)
    

    but to fulfill this, inv (g j) would have needed to either

    • evaluate g j (B1 : repeat B0) to a depth of n+j > n
    • evaluate head $ g j l for at least n different lists matching replicate (n+j) B0 ++ B1 : ls

    Up to that point, at least one of the g j is indistinguishable from f, and since inv f hadn't done either of these evaluations, inv could not possibly have told it apart – short of doing some runtime-measurements on its own, which is only possible in the IO Monad.

                                                                                                                                       ⬜

    0 讨论(0)
  • 2020-12-04 06:39

    Tasks like this are almost always undecidable. You can have a solution for some specific functions, but not in general.

    Here, you cannot even recognize which functions have an inverse. Quoting Barendregt, H. P. The Lambda Calculus: Its Syntax and Semantics. North Holland, Amsterdam (1984):

    A set of lambda-terms is nontrivial if it is neither the empty nor the full set. If A and B are two nontrivial, disjoint sets of lambda-terms closed under (beta) equality, then A and B are recursively inseparable.

    Let's take A to be the set of lambda terms that represent invertible functions and B the rest. Both are non-empty and closed under beta equality. So it's not possible to decide whether a function is invertible or not.

    (This applies to the untyped lambda calculus. TBH I don't know if the argument can be directly adapted to a typed lambda calculus when we know the type of a function that we want to invert. But I'm pretty sure it will be similar.)

    0 讨论(0)
  • 2020-12-04 06:39

    In some cases, it is possible to find the inverse of a bijective function by converting it into a symbolic representation. Based on this example, I wrote this Haskell program to find inverses of some simple polynomial functions:

    bijective_function x = x*2+1
    
    main = do
        print $ bijective_function 3
        print $ inverse_function bijective_function (bijective_function 3)
    
    data Expr = X | Const Double |
                Plus Expr Expr | Subtract Expr Expr | Mult Expr Expr | Div Expr Expr |
                Negate Expr | Inverse Expr |
                Exp Expr | Log Expr | Sin Expr | Atanh Expr | Sinh Expr | Acosh Expr | Cosh Expr | Tan Expr | Cos Expr |Asinh Expr|Atan Expr|Acos Expr|Asin Expr|Abs Expr|Signum Expr|Integer
           deriving (Show, Eq)
    
    instance Num Expr where
        (+) = Plus
        (-) = Subtract
        (*) = Mult
        abs = Abs
        signum = Signum
        negate = Negate
        fromInteger a = Const $ fromIntegral a
    
    instance Fractional Expr where
        recip = Inverse
        fromRational a = Const $ realToFrac a
        (/) = Div
    
    instance Floating Expr where
        pi = Const pi
        exp = Exp
        log = Log
        sin = Sin
        atanh = Atanh
        sinh = Sinh
        cosh = Cosh
        acosh = Acosh
        cos = Cos
        tan = Tan
        asin = Asin
        acos = Acos
        atan = Atan
        asinh = Asinh
    
    fromFunction f = f X
    
    toFunction :: Expr -> (Double -> Double)
    toFunction X = \x -> x
    toFunction (Negate a) = \a -> (negate a)
    toFunction (Const a) = const a
    toFunction (Plus a b) = \x -> (toFunction a x) + (toFunction b x)
    toFunction (Subtract a b) = \x -> (toFunction a x) - (toFunction b x)
    toFunction (Mult a b) = \x -> (toFunction a x) * (toFunction b x)
    toFunction (Div a b) = \x -> (toFunction a x) / (toFunction b x)
    
    
    with_function func x = toFunction $ func $ fromFunction x
    
    simplify X = X
    simplify (Div (Const a) (Const b)) = Const (a/b)
    simplify (Mult (Const a) (Const b)) | a == 0 || b == 0 = 0 | otherwise = Const (a*b)
    simplify (Negate (Negate a)) = simplify a
    simplify (Subtract a b) = simplify ( Plus (simplify a) (Negate (simplify b)) )
    simplify (Div a b) | a == b = Const 1.0 | otherwise = simplify (Div (simplify a) (simplify b))
    simplify (Mult a b) = simplify (Mult (simplify a) (simplify b))
    simplify (Const a) = Const a
    simplify (Plus (Const a) (Const b)) = Const (a+b)
    simplify (Plus a (Const b)) = simplify (Plus (Const b) (simplify a))
    simplify (Plus (Mult (Const a) X) (Mult (Const b) X)) = (simplify (Mult (Const (a+b)) X))
    simplify (Plus (Const a) b) = simplify (Plus (simplify b) (Const a))
    simplify (Plus X a) = simplify (Plus (Mult 1 X) (simplify a))
    simplify (Plus a X) = simplify (Plus (Mult 1 X) (simplify a))
    simplify (Plus a b) = (simplify (Plus (simplify a) (simplify b)))
    simplify a = a
    
    inverse X = X
    inverse (Const a) = simplify (Const a)
    inverse (Mult (Const a) (Const b)) = Const (a * b)
    inverse (Mult (Const a) X) = (Div X (Const a))
    inverse (Plus X (Const a)) = (Subtract X (Const a))
    inverse (Negate x) = Negate (inverse x)
    inverse a = inverse (simplify a)
    
    inverse_function x = with_function inverse x
    

    This example only works with arithmetic expressions, but it could probably be generalized to work with lists as well. There are also several implementations of computer algebra systems in Haskell that may be used to find the inverse of a bijective function.

    0 讨论(0)
  • 2020-12-04 06:43

    You can look it up on wikipedia, it's called Reversible Computing.

    In general you can't do it though and none of the functional languages have that option. For example:

    f :: a -> Int
    f _ = 1
    

    This function does not have an inverse.

    0 讨论(0)
提交回复
热议问题