How to write cache function or equivalent in Python?How to merge two dictionaries in a single expression?How do I check whether a file exists without exceptions?Calling an external command in PythonWhat are metaclasses in Python?Does Python have a ternary conditional operator?How to get the current time in PythonUsing global variables in a functionHow can I make a time delay in Python?How to make a chain of function decorators?Does Python have a string 'contains' substring method?

When I press the space bar it deletes the letters in front of it

What the real concept of Static keyword in perspective of Embedded C. See below code

Given a 32 bit number, what is an efficient way to scale each byte by a certain factor?

When did "&" stop being taught alongside the alphabet?

Misspelling my name on my mathematical publications

Are there any sports for which the world's best player is female?

How quality assurance engineers test calculations?

Integer Lists of Noah

What minifigure is this?

Is "I do not want you to go nowhere" a case of "DOUBLE-NEGATIVES" as claimed by Grammarly?

Apollo astronauts were charged for their berth during their missions?

LMOP: what beasts live in Neverwinter Wood?

How to drill holes in 3/8" steel plates?

What are the indigenous English words for a prostitute?

Data Encryption by Application vs Data Encryption in Database

Can Jimmy hang on his rope?

Why did Harry Potter get a bedroom?

When an electron changes its spin, or any other intrinsic property, is it still the same electron?

A horrible Stockfish chess engine evaluation

Why different specifications for telescopes and binoculars?

Is it OK to leave real names & info visible in business card portfolio?

What's the point of having a RAID 1 configuration over incremental backups to a secondary drive?

Is this a reference to the film Alien in the novel 2010 Odyssey Two?

Graduate student with abysmal English writing skills, how to help



How to write cache function or equivalent in Python?


How to merge two dictionaries in a single expression?How do I check whether a file exists without exceptions?Calling an external command in PythonWhat are metaclasses in Python?Does Python have a ternary conditional operator?How to get the current time in PythonUsing global variables in a functionHow can I make a time delay in Python?How to make a chain of function decorators?Does Python have a string 'contains' substring method?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








7















Question from Daily Coding Problem 210 as reproduced below:



A Collatz sequence in mathematics can be defined as follows. Starting with any positive integer:



if n is even, the next number in the sequence is n / 2
if n is odd, the next number in the sequence is 3n + 1


It is conjectured that every such sequence eventually reaches the number 1. Test this conjecture.



Bonus: What input n <= 1000000 gives the longest sequence?



My code (note that it is incomplete):



def collatz(n):
sequenceLength = 0
while (n>=1):
if (n==1):
break # solution is found
elif (n%2==0):
n = n/2
sequenceLength += 1
else:
n = 3*n+1
sequenceLength += 1
return(sequenceLength)

def longest_seq(limit):
result = []
for i in range(1, limit+1):
result += [collatz(i)]
print(result)
return max(result)


Question:
In this case, I need to test the conjecture that I will always reach "1" for all positive integers. However, my code above assumes this which means I could potentially run an infinite loop.



What is a good/elegant method to test the conjecture? I was thinking something along the lines of a cache/array to see if values of "n" are repeated at the beginning of the while loop. If so, it suggests an infinite loop. However, I am a bit stuck on the syntax part and not clear on the examples I've seen so far. I just need a way to:
- Add things to a cache/equivalent
- Check whether something exists within the cache/equivalent (and this either gives me a proper return or an elegant invalid response that I can use, without crashing my program)



Much thanks.










share|improve this question

















  • 4





    Change n/2 to n//2. In Python 2 they're the same, but in Python 3 / will convert to floating point, while // will give you integer division, which is what you want.

    – Tom Karzes
    Jul 1 at 7:59

















7















Question from Daily Coding Problem 210 as reproduced below:



A Collatz sequence in mathematics can be defined as follows. Starting with any positive integer:



if n is even, the next number in the sequence is n / 2
if n is odd, the next number in the sequence is 3n + 1


It is conjectured that every such sequence eventually reaches the number 1. Test this conjecture.



Bonus: What input n <= 1000000 gives the longest sequence?



My code (note that it is incomplete):



def collatz(n):
sequenceLength = 0
while (n>=1):
if (n==1):
break # solution is found
elif (n%2==0):
n = n/2
sequenceLength += 1
else:
n = 3*n+1
sequenceLength += 1
return(sequenceLength)

def longest_seq(limit):
result = []
for i in range(1, limit+1):
result += [collatz(i)]
print(result)
return max(result)


Question:
In this case, I need to test the conjecture that I will always reach "1" for all positive integers. However, my code above assumes this which means I could potentially run an infinite loop.



What is a good/elegant method to test the conjecture? I was thinking something along the lines of a cache/array to see if values of "n" are repeated at the beginning of the while loop. If so, it suggests an infinite loop. However, I am a bit stuck on the syntax part and not clear on the examples I've seen so far. I just need a way to:
- Add things to a cache/equivalent
- Check whether something exists within the cache/equivalent (and this either gives me a proper return or an elegant invalid response that I can use, without crashing my program)



Much thanks.










share|improve this question

















  • 4





    Change n/2 to n//2. In Python 2 they're the same, but in Python 3 / will convert to floating point, while // will give you integer division, which is what you want.

    – Tom Karzes
    Jul 1 at 7:59













7












7








7








Question from Daily Coding Problem 210 as reproduced below:



A Collatz sequence in mathematics can be defined as follows. Starting with any positive integer:



if n is even, the next number in the sequence is n / 2
if n is odd, the next number in the sequence is 3n + 1


It is conjectured that every such sequence eventually reaches the number 1. Test this conjecture.



Bonus: What input n <= 1000000 gives the longest sequence?



My code (note that it is incomplete):



def collatz(n):
sequenceLength = 0
while (n>=1):
if (n==1):
break # solution is found
elif (n%2==0):
n = n/2
sequenceLength += 1
else:
n = 3*n+1
sequenceLength += 1
return(sequenceLength)

def longest_seq(limit):
result = []
for i in range(1, limit+1):
result += [collatz(i)]
print(result)
return max(result)


Question:
In this case, I need to test the conjecture that I will always reach "1" for all positive integers. However, my code above assumes this which means I could potentially run an infinite loop.



What is a good/elegant method to test the conjecture? I was thinking something along the lines of a cache/array to see if values of "n" are repeated at the beginning of the while loop. If so, it suggests an infinite loop. However, I am a bit stuck on the syntax part and not clear on the examples I've seen so far. I just need a way to:
- Add things to a cache/equivalent
- Check whether something exists within the cache/equivalent (and this either gives me a proper return or an elegant invalid response that I can use, without crashing my program)



Much thanks.










share|improve this question














Question from Daily Coding Problem 210 as reproduced below:



A Collatz sequence in mathematics can be defined as follows. Starting with any positive integer:



if n is even, the next number in the sequence is n / 2
if n is odd, the next number in the sequence is 3n + 1


It is conjectured that every such sequence eventually reaches the number 1. Test this conjecture.



Bonus: What input n <= 1000000 gives the longest sequence?



My code (note that it is incomplete):



def collatz(n):
sequenceLength = 0
while (n>=1):
if (n==1):
break # solution is found
elif (n%2==0):
n = n/2
sequenceLength += 1
else:
n = 3*n+1
sequenceLength += 1
return(sequenceLength)

def longest_seq(limit):
result = []
for i in range(1, limit+1):
result += [collatz(i)]
print(result)
return max(result)


Question:
In this case, I need to test the conjecture that I will always reach "1" for all positive integers. However, my code above assumes this which means I could potentially run an infinite loop.



What is a good/elegant method to test the conjecture? I was thinking something along the lines of a cache/array to see if values of "n" are repeated at the beginning of the while loop. If so, it suggests an infinite loop. However, I am a bit stuck on the syntax part and not clear on the examples I've seen so far. I just need a way to:
- Add things to a cache/equivalent
- Check whether something exists within the cache/equivalent (and this either gives me a proper return or an elegant invalid response that I can use, without crashing my program)



Much thanks.







python






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jul 1 at 7:54









CalvinCalvin

384 bronze badges




384 bronze badges







  • 4





    Change n/2 to n//2. In Python 2 they're the same, but in Python 3 / will convert to floating point, while // will give you integer division, which is what you want.

    – Tom Karzes
    Jul 1 at 7:59












  • 4





    Change n/2 to n//2. In Python 2 they're the same, but in Python 3 / will convert to floating point, while // will give you integer division, which is what you want.

    – Tom Karzes
    Jul 1 at 7:59







4




4





Change n/2 to n//2. In Python 2 they're the same, but in Python 3 / will convert to floating point, while // will give you integer division, which is what you want.

– Tom Karzes
Jul 1 at 7:59





Change n/2 to n//2. In Python 2 they're the same, but in Python 3 / will convert to floating point, while // will give you integer division, which is what you want.

– Tom Karzes
Jul 1 at 7:59












6 Answers
6






active

oldest

votes


















6














Since every time you encounter a specific number n_i you will do the same operation, you know that if you encounter a number that you have already seen then you will loop infinitely.



One way to solve this is to save your sequence. Then you can verify at each step that you haven't already encountered the number. Here is what it could look like :



def collatz(n):
sequence = []
while (n>=1):
if n in sequence:
break
else:
sequence.append(n)
if (n==1):
break # solution is found
elif (n%2==0):
n = n/2
else:
n = 3*n+1
return(sequence)


Note : You can use a set instead of an array if you want the code to run faster since arrays have longer lookup time (credit to @tobias_k). But you will lose the exact order of your sequence.






share|improve this answer




















  • 2





    Plus one for answering the actual question, but a set would be better, as [] has O(n) lookup time.

    – tobias_k
    Jul 1 at 8:48











  • I didn't think about set, thanks for the tip. But since we are working with sequences I think I will keep an array since it allows us to have access to the exact sequence. I added a note to my answer to add your comment since it can be useful if you want fast computations

    – vlemaistre
    Jul 1 at 9:10






  • 3





    Yes, the list has the benefit that you can return the actual Collatz Sequence, but (a) OP does not seem to need that at all, and (b) if you do so, you can just as well drop the sequenceLength variable.

    – tobias_k
    Jul 1 at 9:42






  • 2





    You could have both a list and a set :)

    – NikoNyrh
    Jul 1 at 17:23


















3














There is a built-in decorator for this purpose in python: lru_cache. But first you should use a recursive function to benefit from decorators.



from functools import lru_cache

@lru_cache()
def collatz(n):
sequenceLength = 0
if n == 1:
return n
elif n % 2 == 0:
return 1 + collatz(n // 2)
else: # n % 2 == 1:
return 1 + collatz(3 * n + 1)


You can check here how it works and modify it to do what you want: https://docs.python.org/3/library/functools.html



You want to check if an input has already been seen before, you can define your own decorator:



def deco(f):
cache =
@wraps(f)
def wrapper(*args, **kwargs):
if 'r' in kwargs and kwargs['r']: # reset the cache when first called
cache.clear()
try:
res = cache[args]
# We have already seen these parameters !
print('cache hit', *args)
if res is None:
raise KeyError
except KeyError:
cache[args] = None # temporary store a value here
res = f(*args)
cache[args] = res # final value stored
return res

return wrapper


You just need to change your definition of collatz:



@deco
def collatz(n, /): # force positional argument here
# ... (same code here)


And call it with a reset:



collatz(10, r=True)
>>> 7


But as tobias said, this code should never trigger for collatz function






share|improve this answer




















  • 1





    Note that this is not actually what OP is asking, if you read the last paragraph of the question...

    – tobias_k
    Jul 1 at 8:46











  • @pLOPeGG: Thanks for your answer. I came across something like you have written. I believe it's a form of memoization, with cache being another possibility?

    – Calvin
    Jul 1 at 13:17











  • Memoization is another word for cache applied to speed up recursion IMO.

    – pLOPeGG
    Jul 1 at 13:39


















2














Recursion + caching:



cache = 1:0
def collatz(n):
if n in cache:
return cache[n]
else:
if n%2==0:
m = n//2
else:
m = 3*n+1
res = collatz(m) + 1
cache[n] = res
return res


def longest_seq(limit):
result = []
for i in range(1, limit+1):
result += [collatz(i)]
return max(result)


Then running:



r = longest_seq(1000000)
#524


Find the value corresponding to the max:



[x for x,y in cache.items() if y==r]
#[837799]





share|improve this answer























  • Thanks Nicola. This was the second part I would have looked for!

    – Calvin
    Jul 1 at 13:15


















0














cache = 
def collatz(n):
sequenceLength = 0
while (n>=1):
if n in cache: # number already encountered
return sequenceLength + cache[n]
if (n==1):
break # solution is found
elif (n%2==0):
n = n/2
sequenceLength += 1
else:
n = 3*n+1
sequenceLength += 1
return sequenceLength

def longest_seq(limit):
result = []
for i in range(1, limit+1):
c = collatz(i)
result.append(c)
cache[i] = c # put the answer in the cache

print(result)
return max(result)





share|improve this answer






























    0














    Due to collatz conjecture always ending with 1 I don't see the need to do cached equivalence check. But extra checking never hurts therefore you could just do the simplest ternary check n1 = n if n1 != n else exit() assigning the variables n1 = 0 for the first round before.






    share|improve this answer






























      0














      As already noted, you can use functools.lru_cache to add caching to pretty much any function (with hashable parameters), but in it's current form, caching won't help much with your collatz function, as you call it just once for any parameter. Thus you have a lot of cached values, but you never use any of those. Instead, you could change your function from iterative to recursive to make use of caching:



      @functools.lru_cache()
      def collatz(n):
      if n <= 1:
      return 0
      if n % 2 == 0:
      return 1 + collatz(n // 2)
      else:
      return 1 + collatz(3*n + 1)


      This way, you can reuse a once-calculated result in a later call of collatz if you merge into a "branch" you already explored in an earlier call (there are some nice graphs e.g. in the Wikipedia article of the conjecture.



      Note that depending on the size of your input, you might run into the recursion limit. To "fix" this, you could use sys.setrecursionlimit(somelargenumber) to increase the recursion limit, but of course this only works up to some point.




      However, this seems not to be what you actually asked for (and also does not significantly speed up the code for finding the longest sequence up to 1,000,000). Instead, it seems like you want to check if you find a "loop" during one call of the collatz function. Here, lru_cache won't help. Instead, you should just add a set of already seen values of n and see whether the current number is already in that set. However, I would not expect this code to ever be triggered...



      def collatz(n):
      sequenceLength = 0
      seen = set()
      while (n>=1):
      if n in seen:
      print("BREAKING NEWS! COLLATZ CONJECTURE DISPROVEN!")
      break
      seen.add(n)
      # remainder of your code





      share|improve this answer



























        Your Answer






        StackExchange.ifUsing("editor", function ()
        StackExchange.using("externalEditor", function ()
        StackExchange.using("snippets", function ()
        StackExchange.snippets.init();
        );
        );
        , "code-snippets");

        StackExchange.ready(function()
        var channelOptions =
        tags: "".split(" "),
        id: "1"
        ;
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function()
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled)
        StackExchange.using("snippets", function()
        createEditor();
        );

        else
        createEditor();

        );

        function createEditor()
        StackExchange.prepareEditor(
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader:
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        ,
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        );



        );













        draft saved

        draft discarded


















        StackExchange.ready(
        function ()
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56831892%2fhow-to-write-cache-function-or-equivalent-in-python%23new-answer', 'question_page');

        );

        Post as a guest















        Required, but never shown

























        6 Answers
        6






        active

        oldest

        votes








        6 Answers
        6






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        6














        Since every time you encounter a specific number n_i you will do the same operation, you know that if you encounter a number that you have already seen then you will loop infinitely.



        One way to solve this is to save your sequence. Then you can verify at each step that you haven't already encountered the number. Here is what it could look like :



        def collatz(n):
        sequence = []
        while (n>=1):
        if n in sequence:
        break
        else:
        sequence.append(n)
        if (n==1):
        break # solution is found
        elif (n%2==0):
        n = n/2
        else:
        n = 3*n+1
        return(sequence)


        Note : You can use a set instead of an array if you want the code to run faster since arrays have longer lookup time (credit to @tobias_k). But you will lose the exact order of your sequence.






        share|improve this answer




















        • 2





          Plus one for answering the actual question, but a set would be better, as [] has O(n) lookup time.

          – tobias_k
          Jul 1 at 8:48











        • I didn't think about set, thanks for the tip. But since we are working with sequences I think I will keep an array since it allows us to have access to the exact sequence. I added a note to my answer to add your comment since it can be useful if you want fast computations

          – vlemaistre
          Jul 1 at 9:10






        • 3





          Yes, the list has the benefit that you can return the actual Collatz Sequence, but (a) OP does not seem to need that at all, and (b) if you do so, you can just as well drop the sequenceLength variable.

          – tobias_k
          Jul 1 at 9:42






        • 2





          You could have both a list and a set :)

          – NikoNyrh
          Jul 1 at 17:23















        6














        Since every time you encounter a specific number n_i you will do the same operation, you know that if you encounter a number that you have already seen then you will loop infinitely.



        One way to solve this is to save your sequence. Then you can verify at each step that you haven't already encountered the number. Here is what it could look like :



        def collatz(n):
        sequence = []
        while (n>=1):
        if n in sequence:
        break
        else:
        sequence.append(n)
        if (n==1):
        break # solution is found
        elif (n%2==0):
        n = n/2
        else:
        n = 3*n+1
        return(sequence)


        Note : You can use a set instead of an array if you want the code to run faster since arrays have longer lookup time (credit to @tobias_k). But you will lose the exact order of your sequence.






        share|improve this answer




















        • 2





          Plus one for answering the actual question, but a set would be better, as [] has O(n) lookup time.

          – tobias_k
          Jul 1 at 8:48











        • I didn't think about set, thanks for the tip. But since we are working with sequences I think I will keep an array since it allows us to have access to the exact sequence. I added a note to my answer to add your comment since it can be useful if you want fast computations

          – vlemaistre
          Jul 1 at 9:10






        • 3





          Yes, the list has the benefit that you can return the actual Collatz Sequence, but (a) OP does not seem to need that at all, and (b) if you do so, you can just as well drop the sequenceLength variable.

          – tobias_k
          Jul 1 at 9:42






        • 2





          You could have both a list and a set :)

          – NikoNyrh
          Jul 1 at 17:23













        6












        6








        6







        Since every time you encounter a specific number n_i you will do the same operation, you know that if you encounter a number that you have already seen then you will loop infinitely.



        One way to solve this is to save your sequence. Then you can verify at each step that you haven't already encountered the number. Here is what it could look like :



        def collatz(n):
        sequence = []
        while (n>=1):
        if n in sequence:
        break
        else:
        sequence.append(n)
        if (n==1):
        break # solution is found
        elif (n%2==0):
        n = n/2
        else:
        n = 3*n+1
        return(sequence)


        Note : You can use a set instead of an array if you want the code to run faster since arrays have longer lookup time (credit to @tobias_k). But you will lose the exact order of your sequence.






        share|improve this answer















        Since every time you encounter a specific number n_i you will do the same operation, you know that if you encounter a number that you have already seen then you will loop infinitely.



        One way to solve this is to save your sequence. Then you can verify at each step that you haven't already encountered the number. Here is what it could look like :



        def collatz(n):
        sequence = []
        while (n>=1):
        if n in sequence:
        break
        else:
        sequence.append(n)
        if (n==1):
        break # solution is found
        elif (n%2==0):
        n = n/2
        else:
        n = 3*n+1
        return(sequence)


        Note : You can use a set instead of an array if you want the code to run faster since arrays have longer lookup time (credit to @tobias_k). But you will lose the exact order of your sequence.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jul 1 at 9:49

























        answered Jul 1 at 8:03









        vlemaistrevlemaistre

        1,9043 silver badges20 bronze badges




        1,9043 silver badges20 bronze badges







        • 2





          Plus one for answering the actual question, but a set would be better, as [] has O(n) lookup time.

          – tobias_k
          Jul 1 at 8:48











        • I didn't think about set, thanks for the tip. But since we are working with sequences I think I will keep an array since it allows us to have access to the exact sequence. I added a note to my answer to add your comment since it can be useful if you want fast computations

          – vlemaistre
          Jul 1 at 9:10






        • 3





          Yes, the list has the benefit that you can return the actual Collatz Sequence, but (a) OP does not seem to need that at all, and (b) if you do so, you can just as well drop the sequenceLength variable.

          – tobias_k
          Jul 1 at 9:42






        • 2





          You could have both a list and a set :)

          – NikoNyrh
          Jul 1 at 17:23












        • 2





          Plus one for answering the actual question, but a set would be better, as [] has O(n) lookup time.

          – tobias_k
          Jul 1 at 8:48











        • I didn't think about set, thanks for the tip. But since we are working with sequences I think I will keep an array since it allows us to have access to the exact sequence. I added a note to my answer to add your comment since it can be useful if you want fast computations

          – vlemaistre
          Jul 1 at 9:10






        • 3





          Yes, the list has the benefit that you can return the actual Collatz Sequence, but (a) OP does not seem to need that at all, and (b) if you do so, you can just as well drop the sequenceLength variable.

          – tobias_k
          Jul 1 at 9:42






        • 2





          You could have both a list and a set :)

          – NikoNyrh
          Jul 1 at 17:23







        2




        2





        Plus one for answering the actual question, but a set would be better, as [] has O(n) lookup time.

        – tobias_k
        Jul 1 at 8:48





        Plus one for answering the actual question, but a set would be better, as [] has O(n) lookup time.

        – tobias_k
        Jul 1 at 8:48













        I didn't think about set, thanks for the tip. But since we are working with sequences I think I will keep an array since it allows us to have access to the exact sequence. I added a note to my answer to add your comment since it can be useful if you want fast computations

        – vlemaistre
        Jul 1 at 9:10





        I didn't think about set, thanks for the tip. But since we are working with sequences I think I will keep an array since it allows us to have access to the exact sequence. I added a note to my answer to add your comment since it can be useful if you want fast computations

        – vlemaistre
        Jul 1 at 9:10




        3




        3





        Yes, the list has the benefit that you can return the actual Collatz Sequence, but (a) OP does not seem to need that at all, and (b) if you do so, you can just as well drop the sequenceLength variable.

        – tobias_k
        Jul 1 at 9:42





        Yes, the list has the benefit that you can return the actual Collatz Sequence, but (a) OP does not seem to need that at all, and (b) if you do so, you can just as well drop the sequenceLength variable.

        – tobias_k
        Jul 1 at 9:42




        2




        2





        You could have both a list and a set :)

        – NikoNyrh
        Jul 1 at 17:23





        You could have both a list and a set :)

        – NikoNyrh
        Jul 1 at 17:23













        3














        There is a built-in decorator for this purpose in python: lru_cache. But first you should use a recursive function to benefit from decorators.



        from functools import lru_cache

        @lru_cache()
        def collatz(n):
        sequenceLength = 0
        if n == 1:
        return n
        elif n % 2 == 0:
        return 1 + collatz(n // 2)
        else: # n % 2 == 1:
        return 1 + collatz(3 * n + 1)


        You can check here how it works and modify it to do what you want: https://docs.python.org/3/library/functools.html



        You want to check if an input has already been seen before, you can define your own decorator:



        def deco(f):
        cache =
        @wraps(f)
        def wrapper(*args, **kwargs):
        if 'r' in kwargs and kwargs['r']: # reset the cache when first called
        cache.clear()
        try:
        res = cache[args]
        # We have already seen these parameters !
        print('cache hit', *args)
        if res is None:
        raise KeyError
        except KeyError:
        cache[args] = None # temporary store a value here
        res = f(*args)
        cache[args] = res # final value stored
        return res

        return wrapper


        You just need to change your definition of collatz:



        @deco
        def collatz(n, /): # force positional argument here
        # ... (same code here)


        And call it with a reset:



        collatz(10, r=True)
        >>> 7


        But as tobias said, this code should never trigger for collatz function






        share|improve this answer




















        • 1





          Note that this is not actually what OP is asking, if you read the last paragraph of the question...

          – tobias_k
          Jul 1 at 8:46











        • @pLOPeGG: Thanks for your answer. I came across something like you have written. I believe it's a form of memoization, with cache being another possibility?

          – Calvin
          Jul 1 at 13:17











        • Memoization is another word for cache applied to speed up recursion IMO.

          – pLOPeGG
          Jul 1 at 13:39















        3














        There is a built-in decorator for this purpose in python: lru_cache. But first you should use a recursive function to benefit from decorators.



        from functools import lru_cache

        @lru_cache()
        def collatz(n):
        sequenceLength = 0
        if n == 1:
        return n
        elif n % 2 == 0:
        return 1 + collatz(n // 2)
        else: # n % 2 == 1:
        return 1 + collatz(3 * n + 1)


        You can check here how it works and modify it to do what you want: https://docs.python.org/3/library/functools.html



        You want to check if an input has already been seen before, you can define your own decorator:



        def deco(f):
        cache =
        @wraps(f)
        def wrapper(*args, **kwargs):
        if 'r' in kwargs and kwargs['r']: # reset the cache when first called
        cache.clear()
        try:
        res = cache[args]
        # We have already seen these parameters !
        print('cache hit', *args)
        if res is None:
        raise KeyError
        except KeyError:
        cache[args] = None # temporary store a value here
        res = f(*args)
        cache[args] = res # final value stored
        return res

        return wrapper


        You just need to change your definition of collatz:



        @deco
        def collatz(n, /): # force positional argument here
        # ... (same code here)


        And call it with a reset:



        collatz(10, r=True)
        >>> 7


        But as tobias said, this code should never trigger for collatz function






        share|improve this answer




















        • 1





          Note that this is not actually what OP is asking, if you read the last paragraph of the question...

          – tobias_k
          Jul 1 at 8:46











        • @pLOPeGG: Thanks for your answer. I came across something like you have written. I believe it's a form of memoization, with cache being another possibility?

          – Calvin
          Jul 1 at 13:17











        • Memoization is another word for cache applied to speed up recursion IMO.

          – pLOPeGG
          Jul 1 at 13:39













        3












        3








        3







        There is a built-in decorator for this purpose in python: lru_cache. But first you should use a recursive function to benefit from decorators.



        from functools import lru_cache

        @lru_cache()
        def collatz(n):
        sequenceLength = 0
        if n == 1:
        return n
        elif n % 2 == 0:
        return 1 + collatz(n // 2)
        else: # n % 2 == 1:
        return 1 + collatz(3 * n + 1)


        You can check here how it works and modify it to do what you want: https://docs.python.org/3/library/functools.html



        You want to check if an input has already been seen before, you can define your own decorator:



        def deco(f):
        cache =
        @wraps(f)
        def wrapper(*args, **kwargs):
        if 'r' in kwargs and kwargs['r']: # reset the cache when first called
        cache.clear()
        try:
        res = cache[args]
        # We have already seen these parameters !
        print('cache hit', *args)
        if res is None:
        raise KeyError
        except KeyError:
        cache[args] = None # temporary store a value here
        res = f(*args)
        cache[args] = res # final value stored
        return res

        return wrapper


        You just need to change your definition of collatz:



        @deco
        def collatz(n, /): # force positional argument here
        # ... (same code here)


        And call it with a reset:



        collatz(10, r=True)
        >>> 7


        But as tobias said, this code should never trigger for collatz function






        share|improve this answer















        There is a built-in decorator for this purpose in python: lru_cache. But first you should use a recursive function to benefit from decorators.



        from functools import lru_cache

        @lru_cache()
        def collatz(n):
        sequenceLength = 0
        if n == 1:
        return n
        elif n % 2 == 0:
        return 1 + collatz(n // 2)
        else: # n % 2 == 1:
        return 1 + collatz(3 * n + 1)


        You can check here how it works and modify it to do what you want: https://docs.python.org/3/library/functools.html



        You want to check if an input has already been seen before, you can define your own decorator:



        def deco(f):
        cache =
        @wraps(f)
        def wrapper(*args, **kwargs):
        if 'r' in kwargs and kwargs['r']: # reset the cache when first called
        cache.clear()
        try:
        res = cache[args]
        # We have already seen these parameters !
        print('cache hit', *args)
        if res is None:
        raise KeyError
        except KeyError:
        cache[args] = None # temporary store a value here
        res = f(*args)
        cache[args] = res # final value stored
        return res

        return wrapper


        You just need to change your definition of collatz:



        @deco
        def collatz(n, /): # force positional argument here
        # ... (same code here)


        And call it with a reset:



        collatz(10, r=True)
        >>> 7


        But as tobias said, this code should never trigger for collatz function







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jul 1 at 9:48

























        answered Jul 1 at 7:59









        pLOPeGGpLOPeGG

        7473 silver badges15 bronze badges




        7473 silver badges15 bronze badges







        • 1





          Note that this is not actually what OP is asking, if you read the last paragraph of the question...

          – tobias_k
          Jul 1 at 8:46











        • @pLOPeGG: Thanks for your answer. I came across something like you have written. I believe it's a form of memoization, with cache being another possibility?

          – Calvin
          Jul 1 at 13:17











        • Memoization is another word for cache applied to speed up recursion IMO.

          – pLOPeGG
          Jul 1 at 13:39












        • 1





          Note that this is not actually what OP is asking, if you read the last paragraph of the question...

          – tobias_k
          Jul 1 at 8:46











        • @pLOPeGG: Thanks for your answer. I came across something like you have written. I believe it's a form of memoization, with cache being another possibility?

          – Calvin
          Jul 1 at 13:17











        • Memoization is another word for cache applied to speed up recursion IMO.

          – pLOPeGG
          Jul 1 at 13:39







        1




        1





        Note that this is not actually what OP is asking, if you read the last paragraph of the question...

        – tobias_k
        Jul 1 at 8:46





        Note that this is not actually what OP is asking, if you read the last paragraph of the question...

        – tobias_k
        Jul 1 at 8:46













        @pLOPeGG: Thanks for your answer. I came across something like you have written. I believe it's a form of memoization, with cache being another possibility?

        – Calvin
        Jul 1 at 13:17





        @pLOPeGG: Thanks for your answer. I came across something like you have written. I believe it's a form of memoization, with cache being another possibility?

        – Calvin
        Jul 1 at 13:17













        Memoization is another word for cache applied to speed up recursion IMO.

        – pLOPeGG
        Jul 1 at 13:39





        Memoization is another word for cache applied to speed up recursion IMO.

        – pLOPeGG
        Jul 1 at 13:39











        2














        Recursion + caching:



        cache = 1:0
        def collatz(n):
        if n in cache:
        return cache[n]
        else:
        if n%2==0:
        m = n//2
        else:
        m = 3*n+1
        res = collatz(m) + 1
        cache[n] = res
        return res


        def longest_seq(limit):
        result = []
        for i in range(1, limit+1):
        result += [collatz(i)]
        return max(result)


        Then running:



        r = longest_seq(1000000)
        #524


        Find the value corresponding to the max:



        [x for x,y in cache.items() if y==r]
        #[837799]





        share|improve this answer























        • Thanks Nicola. This was the second part I would have looked for!

          – Calvin
          Jul 1 at 13:15















        2














        Recursion + caching:



        cache = 1:0
        def collatz(n):
        if n in cache:
        return cache[n]
        else:
        if n%2==0:
        m = n//2
        else:
        m = 3*n+1
        res = collatz(m) + 1
        cache[n] = res
        return res


        def longest_seq(limit):
        result = []
        for i in range(1, limit+1):
        result += [collatz(i)]
        return max(result)


        Then running:



        r = longest_seq(1000000)
        #524


        Find the value corresponding to the max:



        [x for x,y in cache.items() if y==r]
        #[837799]





        share|improve this answer























        • Thanks Nicola. This was the second part I would have looked for!

          – Calvin
          Jul 1 at 13:15













        2












        2








        2







        Recursion + caching:



        cache = 1:0
        def collatz(n):
        if n in cache:
        return cache[n]
        else:
        if n%2==0:
        m = n//2
        else:
        m = 3*n+1
        res = collatz(m) + 1
        cache[n] = res
        return res


        def longest_seq(limit):
        result = []
        for i in range(1, limit+1):
        result += [collatz(i)]
        return max(result)


        Then running:



        r = longest_seq(1000000)
        #524


        Find the value corresponding to the max:



        [x for x,y in cache.items() if y==r]
        #[837799]





        share|improve this answer













        Recursion + caching:



        cache = 1:0
        def collatz(n):
        if n in cache:
        return cache[n]
        else:
        if n%2==0:
        m = n//2
        else:
        m = 3*n+1
        res = collatz(m) + 1
        cache[n] = res
        return res


        def longest_seq(limit):
        result = []
        for i in range(1, limit+1):
        result += [collatz(i)]
        return max(result)


        Then running:



        r = longest_seq(1000000)
        #524


        Find the value corresponding to the max:



        [x for x,y in cache.items() if y==r]
        #[837799]






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Jul 1 at 8:27









        nicolanicola

        19.7k2 gold badges19 silver badges38 bronze badges




        19.7k2 gold badges19 silver badges38 bronze badges












        • Thanks Nicola. This was the second part I would have looked for!

          – Calvin
          Jul 1 at 13:15

















        • Thanks Nicola. This was the second part I would have looked for!

          – Calvin
          Jul 1 at 13:15
















        Thanks Nicola. This was the second part I would have looked for!

        – Calvin
        Jul 1 at 13:15





        Thanks Nicola. This was the second part I would have looked for!

        – Calvin
        Jul 1 at 13:15











        0














        cache = 
        def collatz(n):
        sequenceLength = 0
        while (n>=1):
        if n in cache: # number already encountered
        return sequenceLength + cache[n]
        if (n==1):
        break # solution is found
        elif (n%2==0):
        n = n/2
        sequenceLength += 1
        else:
        n = 3*n+1
        sequenceLength += 1
        return sequenceLength

        def longest_seq(limit):
        result = []
        for i in range(1, limit+1):
        c = collatz(i)
        result.append(c)
        cache[i] = c # put the answer in the cache

        print(result)
        return max(result)





        share|improve this answer



























          0














          cache = 
          def collatz(n):
          sequenceLength = 0
          while (n>=1):
          if n in cache: # number already encountered
          return sequenceLength + cache[n]
          if (n==1):
          break # solution is found
          elif (n%2==0):
          n = n/2
          sequenceLength += 1
          else:
          n = 3*n+1
          sequenceLength += 1
          return sequenceLength

          def longest_seq(limit):
          result = []
          for i in range(1, limit+1):
          c = collatz(i)
          result.append(c)
          cache[i] = c # put the answer in the cache

          print(result)
          return max(result)





          share|improve this answer

























            0












            0








            0







            cache = 
            def collatz(n):
            sequenceLength = 0
            while (n>=1):
            if n in cache: # number already encountered
            return sequenceLength + cache[n]
            if (n==1):
            break # solution is found
            elif (n%2==0):
            n = n/2
            sequenceLength += 1
            else:
            n = 3*n+1
            sequenceLength += 1
            return sequenceLength

            def longest_seq(limit):
            result = []
            for i in range(1, limit+1):
            c = collatz(i)
            result.append(c)
            cache[i] = c # put the answer in the cache

            print(result)
            return max(result)





            share|improve this answer













            cache = 
            def collatz(n):
            sequenceLength = 0
            while (n>=1):
            if n in cache: # number already encountered
            return sequenceLength + cache[n]
            if (n==1):
            break # solution is found
            elif (n%2==0):
            n = n/2
            sequenceLength += 1
            else:
            n = 3*n+1
            sequenceLength += 1
            return sequenceLength

            def longest_seq(limit):
            result = []
            for i in range(1, limit+1):
            c = collatz(i)
            result.append(c)
            cache[i] = c # put the answer in the cache

            print(result)
            return max(result)






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Jul 1 at 8:06









            ZefickZefick

            1,4059 silver badges16 bronze badges




            1,4059 silver badges16 bronze badges





















                0














                Due to collatz conjecture always ending with 1 I don't see the need to do cached equivalence check. But extra checking never hurts therefore you could just do the simplest ternary check n1 = n if n1 != n else exit() assigning the variables n1 = 0 for the first round before.






                share|improve this answer



























                  0














                  Due to collatz conjecture always ending with 1 I don't see the need to do cached equivalence check. But extra checking never hurts therefore you could just do the simplest ternary check n1 = n if n1 != n else exit() assigning the variables n1 = 0 for the first round before.






                  share|improve this answer

























                    0












                    0








                    0







                    Due to collatz conjecture always ending with 1 I don't see the need to do cached equivalence check. But extra checking never hurts therefore you could just do the simplest ternary check n1 = n if n1 != n else exit() assigning the variables n1 = 0 for the first round before.






                    share|improve this answer













                    Due to collatz conjecture always ending with 1 I don't see the need to do cached equivalence check. But extra checking never hurts therefore you could just do the simplest ternary check n1 = n if n1 != n else exit() assigning the variables n1 = 0 for the first round before.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jul 1 at 8:16









                    AjamaAjama

                    689 bronze badges




                    689 bronze badges





















                        0














                        As already noted, you can use functools.lru_cache to add caching to pretty much any function (with hashable parameters), but in it's current form, caching won't help much with your collatz function, as you call it just once for any parameter. Thus you have a lot of cached values, but you never use any of those. Instead, you could change your function from iterative to recursive to make use of caching:



                        @functools.lru_cache()
                        def collatz(n):
                        if n <= 1:
                        return 0
                        if n % 2 == 0:
                        return 1 + collatz(n // 2)
                        else:
                        return 1 + collatz(3*n + 1)


                        This way, you can reuse a once-calculated result in a later call of collatz if you merge into a "branch" you already explored in an earlier call (there are some nice graphs e.g. in the Wikipedia article of the conjecture.



                        Note that depending on the size of your input, you might run into the recursion limit. To "fix" this, you could use sys.setrecursionlimit(somelargenumber) to increase the recursion limit, but of course this only works up to some point.




                        However, this seems not to be what you actually asked for (and also does not significantly speed up the code for finding the longest sequence up to 1,000,000). Instead, it seems like you want to check if you find a "loop" during one call of the collatz function. Here, lru_cache won't help. Instead, you should just add a set of already seen values of n and see whether the current number is already in that set. However, I would not expect this code to ever be triggered...



                        def collatz(n):
                        sequenceLength = 0
                        seen = set()
                        while (n>=1):
                        if n in seen:
                        print("BREAKING NEWS! COLLATZ CONJECTURE DISPROVEN!")
                        break
                        seen.add(n)
                        # remainder of your code





                        share|improve this answer





























                          0














                          As already noted, you can use functools.lru_cache to add caching to pretty much any function (with hashable parameters), but in it's current form, caching won't help much with your collatz function, as you call it just once for any parameter. Thus you have a lot of cached values, but you never use any of those. Instead, you could change your function from iterative to recursive to make use of caching:



                          @functools.lru_cache()
                          def collatz(n):
                          if n <= 1:
                          return 0
                          if n % 2 == 0:
                          return 1 + collatz(n // 2)
                          else:
                          return 1 + collatz(3*n + 1)


                          This way, you can reuse a once-calculated result in a later call of collatz if you merge into a "branch" you already explored in an earlier call (there are some nice graphs e.g. in the Wikipedia article of the conjecture.



                          Note that depending on the size of your input, you might run into the recursion limit. To "fix" this, you could use sys.setrecursionlimit(somelargenumber) to increase the recursion limit, but of course this only works up to some point.




                          However, this seems not to be what you actually asked for (and also does not significantly speed up the code for finding the longest sequence up to 1,000,000). Instead, it seems like you want to check if you find a "loop" during one call of the collatz function. Here, lru_cache won't help. Instead, you should just add a set of already seen values of n and see whether the current number is already in that set. However, I would not expect this code to ever be triggered...



                          def collatz(n):
                          sequenceLength = 0
                          seen = set()
                          while (n>=1):
                          if n in seen:
                          print("BREAKING NEWS! COLLATZ CONJECTURE DISPROVEN!")
                          break
                          seen.add(n)
                          # remainder of your code





                          share|improve this answer



























                            0












                            0








                            0







                            As already noted, you can use functools.lru_cache to add caching to pretty much any function (with hashable parameters), but in it's current form, caching won't help much with your collatz function, as you call it just once for any parameter. Thus you have a lot of cached values, but you never use any of those. Instead, you could change your function from iterative to recursive to make use of caching:



                            @functools.lru_cache()
                            def collatz(n):
                            if n <= 1:
                            return 0
                            if n % 2 == 0:
                            return 1 + collatz(n // 2)
                            else:
                            return 1 + collatz(3*n + 1)


                            This way, you can reuse a once-calculated result in a later call of collatz if you merge into a "branch" you already explored in an earlier call (there are some nice graphs e.g. in the Wikipedia article of the conjecture.



                            Note that depending on the size of your input, you might run into the recursion limit. To "fix" this, you could use sys.setrecursionlimit(somelargenumber) to increase the recursion limit, but of course this only works up to some point.




                            However, this seems not to be what you actually asked for (and also does not significantly speed up the code for finding the longest sequence up to 1,000,000). Instead, it seems like you want to check if you find a "loop" during one call of the collatz function. Here, lru_cache won't help. Instead, you should just add a set of already seen values of n and see whether the current number is already in that set. However, I would not expect this code to ever be triggered...



                            def collatz(n):
                            sequenceLength = 0
                            seen = set()
                            while (n>=1):
                            if n in seen:
                            print("BREAKING NEWS! COLLATZ CONJECTURE DISPROVEN!")
                            break
                            seen.add(n)
                            # remainder of your code





                            share|improve this answer















                            As already noted, you can use functools.lru_cache to add caching to pretty much any function (with hashable parameters), but in it's current form, caching won't help much with your collatz function, as you call it just once for any parameter. Thus you have a lot of cached values, but you never use any of those. Instead, you could change your function from iterative to recursive to make use of caching:



                            @functools.lru_cache()
                            def collatz(n):
                            if n <= 1:
                            return 0
                            if n % 2 == 0:
                            return 1 + collatz(n // 2)
                            else:
                            return 1 + collatz(3*n + 1)


                            This way, you can reuse a once-calculated result in a later call of collatz if you merge into a "branch" you already explored in an earlier call (there are some nice graphs e.g. in the Wikipedia article of the conjecture.



                            Note that depending on the size of your input, you might run into the recursion limit. To "fix" this, you could use sys.setrecursionlimit(somelargenumber) to increase the recursion limit, but of course this only works up to some point.




                            However, this seems not to be what you actually asked for (and also does not significantly speed up the code for finding the longest sequence up to 1,000,000). Instead, it seems like you want to check if you find a "loop" during one call of the collatz function. Here, lru_cache won't help. Instead, you should just add a set of already seen values of n and see whether the current number is already in that set. However, I would not expect this code to ever be triggered...



                            def collatz(n):
                            sequenceLength = 0
                            seen = set()
                            while (n>=1):
                            if n in seen:
                            print("BREAKING NEWS! COLLATZ CONJECTURE DISPROVEN!")
                            break
                            seen.add(n)
                            # remainder of your code






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Jul 1 at 9:45

























                            answered Jul 1 at 8:28









                            tobias_ktobias_k

                            61.2k9 gold badges73 silver badges116 bronze badges




                            61.2k9 gold badges73 silver badges116 bronze badges



























                                draft saved

                                draft discarded
















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid


                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.

                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function ()
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56831892%2fhow-to-write-cache-function-or-equivalent-in-python%23new-answer', 'question_page');

                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Category:9 (number) SubcategoriesMedia in category "9 (number)"Navigation menuUpload mediaGND ID: 4485639-8Library of Congress authority ID: sh85091979ReasonatorScholiaStatistics

                                Circuit construction for execution of conditional statements using least significant bitHow are two different registers being used as “control”?How exactly is the stated composite state of the two registers being produced using the $R_zz$ controlled rotations?Efficiently performing controlled rotations in HHLWould this quantum algorithm implementation work?How to prepare a superposed states of odd integers from $1$ to $sqrtN$?Why is this implementation of the order finding algorithm not working?Circuit construction for Hamiltonian simulationHow can I invert the least significant bit of a certain term of a superposed state?Implementing an oracleImplementing a controlled sum operation

                                Magento 2 “No Payment Methods” in Admin New OrderHow to integrate Paypal Express Checkout with the Magento APIMagento 1.5 - Sales > Order > edit order and shipping methods disappearAuto Invoice Check/Money Order Payment methodAdd more simple payment methods?Shipping methods not showingWhat should I do to change payment methods if changing the configuration has no effects?1.9 - No Payment Methods showing upMy Payment Methods not Showing for downloadable/virtual product when checkout?Magento2 API to access internal payment methodHow to call an existing payment methods in the registration form?