@@ -103,4 +103,53 @@ def shitfuck(k, recurrence_counter):
103103 return _shitfuck_cache [(k , recurrence_counter )]
104104
105105
106+
107+
108+ ###############################################################################
109+
110+ _catshit_cache = {}
111+
112+ def catshit (k , recurrence_counter ):
113+ from python_toolbox import nifty_collections
114+ from python_toolbox import cute_iter_tools
115+ if not isinstance (recurrence_counter , nifty_collections .FrozenChunkCounter ):
116+ recurrence_counter = \
117+ nifty_collections .FrozenChunkCounter (recurrence_counter )
118+ if k == 1 :
119+ assert recurrence_counter # Works because `FrozenCounter` implements
120+ # `__bool__`.
121+ return 1
122+ try :
123+ return _catshit_cache [(k , recurrence_counter )]
124+ except KeyError :
125+ pass
126+
127+ levels = []
128+ current_reccurence_counters = {recurrence_counter }
129+ while len (levels ) < k and current_reccurence_counters :
130+ k_ = k - len (levels )
131+ levels .append (
132+ {recurrence_counter_ : recurrence_counter_ .get_sub_counters_counter ()
133+ for recurrence_counter_ in current_reccurence_counters
134+ if (k_ , recurrence_counter_ ) not in _catshit_cache
135+ })
136+ current_reccurence_counters = \
137+ set (itertools .chain (* levels [- 1 ].values ()))
138+
139+ # The last level is calculated. Time to make our way up.
140+ for k_ , level in enumerate (reversed (levels ), (k - len (levels ) + 1 )):
141+ if k_ == 1 :
142+ for recurrence_counter_ , sub_counters_counter in level .items ():
143+ _catshit_cache [(k_ , recurrence_counter_ )] = \
144+ recurrence_counter_ .n_elements
145+ else :
146+ for recurrence_counter_ , sub_counters_counter in level .items ():
147+ _catshit_cache [(k_ , recurrence_counter_ )] = sum (
148+ (_catshit_cache [(k_ - 1 , sub_counter )] * factor for
149+ sub_counter , factor in sub_counters_counter .items ())
150+ )
151+
152+ return _catshit_cache [(k , recurrence_counter )]
153+
154+
106155
0 commit comments