1

I have a string function (and I am sure it is reversible, so no need to test this), could I call it in reverse to perform the opposite operation?

For example:

def sample(s):
    return s[1:]+s[:1]

would put the first letter of a string on the end and return it.

'Output' would become 'utputO'.

When I want to get the opposite operation, could I use this same function?

'utputO' would return 'Output'.

7
  • 1
    I'm sorry, I don't quite understand. Are you trying to invert arbitrary functions (because that's a math question), or invert particular string functions (which might be a python question), or wondering whether python has built-in arbitrary inversion functionality (no, not really possible)? Commented Jun 3, 2016 at 14:53
  • 1
    Okay, that's a much better question :) Could you clarify that in your question ("I have a function", not "if I have a function", which to me sounds way more general), and show what happens in some unit cases and what you believe the behaviour to be? I think you'll get waay better response that way. Commented Jun 3, 2016 at 14:55
  • 1
    Inversion is only possible for side-effect free injective functions. Simply create a lookup table when you execute the function and then reverse-lookup. Just kidding ;) Commented Jun 3, 2016 at 14:56
  • 1
    @nucleon hmm functions have to be bijective (i.e., surjective and injective) to be invertible. I don't see how side-effect-free implies surjective, or is there an implicit embedded condition that provides that, like finite state? Commented Jun 3, 2016 at 15:01
  • 1
    For example, a function that takes strings and maps them to real numbers injectively would not be invertible (there can't exist an "inverse function"), because the spaces don't line up Commented Jun 3, 2016 at 15:03

1 Answer 1

2

Short answer: no.

Longer answer: I can think of 3, maybe 4 ways to approach what you want -- all of which depend on how are you allowed to change your functions (possibly restricting to a sub-set of Python or mini language), train them, or run them normally with the operands you are expecting to invert later.

So, method (1) - would probably not reach 100% determinism, and would require training with a lot of random examples for each function: use a machine learning approach. That is cool, because it is a hot topic, this would be almost a "machine learning hello world" to implement using one of the various frameworks existing for Python or even roll your own - just setup a neural network for string transformation, train it with a couple thousand (maybe just a few hundred) string transformations for each function you want to invert, and you should have the reverse function. I think this could be the best - at least the "least incorrect" approach - at least it will be the more generic one.

Method(2): Create a mini language for string transformation with reversible operands. Write your functions using this mini language. Introspect your functions and generate the reversed ones.

May look weird, but imagine a minimal stack language that could remove an item from a position in a string, and push it on the stack, pop an item to a position on the string, and maybe perform a couple more reversible primitives you might need (say upper/lower) -

OPSTACK = []
language = {
    "push_op": (lambda s, pos: (OPSTACK.append(s[pos]), s[:pos] + s[pos + 1:])[1]),
    "pop_op": (lambda s, pos: s[:pos] + OPSTACK.pop() + s[pos:]),
    "push_end": (lambda s: (OPSTACK.append(s[-1]), s[:-1])[1]),
    "pop_end": lambda s: s + OPSTACK.pop(),
    "lower": lambda s: s.lower(),
    "upper": lambda s: s.upper(),
    # ...
}

# (or pip install extradict and use extradict.BijectiveDict to avoid having to write  double entries)
reverse_mapping =  {
    "push_op": "pop_op",
    "pop_op": "push_op",
    "push_end": "pop_end",
    "pop_end": "push_end",
    "lower": "upper",
    "upper": "lower"
}

def engine(text, function):
    tokens = function.split()
    while tokens:
        operator = tokens.pop(0)
        if operator.endswith("_op"):
            operand = int(tokens.pop(0))
            text = language[operator](text, operand)
        else:
            text = language[operator](text)
    return text

def inverter(function):
    inverted = []
    tokens = function.split()
    while tokens:
        operator = tokens.pop(0)
        inverted.insert(0, reverse_mapping[operator])
        if operator.endswith("_op"):
            operand = tokens.pop(0)
            inverted.insert(1, operand)
    return " ".join(inverted)

Example:

In [36]: sample = "push_op 0 pop_end"

In [37]: engine("Output", sample)
Out[37]: 'utputO'

In [38]: elpmas = inverter(sample)

In [39]: elpmas
Out[39]: 'push_end pop_op 0'

In [40]: engine("utputO", elpmas)
Out[40]: 'Output'

Method 3: If possible, it is easy to cache the input and output of each call, and just use that to operate in reverse - it could be done as a decorator in Python

from functools import wraps

def reverse_cache(func):
    reverse_cache = {}
    wraps(func)
    def wrapper(input_text):
        result = func(input_text)
        reverse_cache[result] = input_text
        return result
    wrapper.reverse_cache = reverse_cache
    return wrapper

Example:

In [3]: @reverse_cache
...     def sample(s):
...        return s[1:]+s[:1]

In [4]:

In [5]: sample("Output")
Out[5]: 'utputO'

In [6]: sample.reverse_cache["utputO"]
Out[6]: 'Output'

Method 4: If the string operations are limited to shuffling the string contents in a deterministic way, like in your example, (and maybe offsetting the character code values by a constant - but no other operations at all), it is possible to write a learner function without the use of neural-network programming: it would construct a string with one character of each (possibly with code-points in ascending order), pass it through the function, and note down the numeric order of the string that was output - so, in your example, the reconstructed output order would be (1,2,3,4,5,0) - given that sequence, one just have to reorder the input for the inverted function according to those indexes - which is trivial in Python:

def order_map(func, length):
    sample_text = "".join(chr(i) for i in range(32, 32 + length))
    result = func(sample_text)
    return [ord(char) - 32 for char in result]

def invert(func, text):
    map_ = order_map(func, len(text))
    reordered = sorted(zip(map_, text))
    return "".join(item[1] for item in reordered)

Example:

In [47]: def sample(s):
   ....:         return s[1:] + s[0]
   ....: 

In [48]: sample("Output")
Out[48]: 'utputO'

In [49]: invert(sample, "uputO")
Out[49]: 'Ouput'

In [50]: 
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.