<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def add_stroke(self, new_stroke):
 """ Update the beam so that it considers `new_stroke`. When a `new_stroke` comes, it can either belong to a symbol for which at least one other stroke was already made or belong to a symbol for which `new_stroke` is the first stroke. The number of hypotheses after q strokes without pruning is f: N_0 -> N_0 f(0) = 1 f(1) = m f(q) = f(q-1)*(m+n) The number of time the single symbol classifier has to be called, when already q hypotheses exist: f_s: N_0 -> N_0 f_s(q) = q*n + 1 (upper bound) Parameters new_stroke : list of dicts represent a point. """

        global single_clf
        if len(self.hypotheses) == 0:  # Don't put this in the constructor!
            self.hypotheses = [{'segmentation': [],
                                'symbols': [],
                                'geometry': {},
                                'probability': Decimal(1)
                                }]
        stroke_nr = len(self.history['data'])
        new_history = deepcopy(self.history)
        new_history['data'].append(new_stroke)
        new_beam = Beam()
        new_beam.history = new_history

        evaluated_segmentations = []

        # Get new guesses by assuming new_stroke belongs to an already begun
        # symbol
        had_multisymbol = False
        for hyp in self.hypotheses:
            # Add stroke to last n symbols (seperately)
            for i in range(min(self.n, len(hyp['segmentation']))):
                # Build stroke data
                new_strokes = {'data': [], 'id': -1}
                for stroke_index in hyp['segmentation'][-(i+1)]:
                    curr_stroke = self.history['data'][stroke_index]
                    new_strokes['data'].append(curr_stroke)
                new_strokes['data'].append(new_stroke)

                new_seg = deepcopy(hyp['segmentation'])
                new_seg[-(i+1)].append(stroke_nr)

                if new_seg in evaluated_segmentations:
                    continue
                else:
                    evaluated_segmentations.append(new_seg)

                # Predict this new collection of strokes
                guesses = single_clf.predict(new_strokes)[:self.m]
                for guess in guesses:
                    if guess['semantics'].split(";")[1] == "::MULTISYMBOL::":
                        # This was a wrong segmentation. Ignore it.
                        had_multisymbol = True
                        continue
                    sym = {'symbol': guess['semantics'],
                           'probability': guess['probability']}
                    new_sym = deepcopy(hyp['symbols'])
                    new_sym[-(i+1)] = sym
                    b = {'segmentation': new_seg,
                         'symbols': new_sym,
                         'geometry': deepcopy(hyp['geometry']),
                         'probability': None
                         }
                    new_beam.hypotheses.append(b)

        if len(self.hypotheses) <= 1 or had_multisymbol:
            self._add_hypotheses_assuming_new_stroke(new_stroke,
                                                     stroke_nr,
                                                     new_beam)

        for hyp in new_beam.hypotheses:
            hyp['probability'] = _calc_hypothesis_probability(hyp)

        # Get probability again

        # Get geometry of each beam entry
        # TODO

        # Update probabilities
        # TODO

        # Normalize to sum=1
        self.hypotheses = new_beam.hypotheses
        self.history = new_beam.history
        self._prune()
        new_probs = softmax([h['probability']
                             for h in self.hypotheses])
        for hyp, prob in zip(self.hypotheses, new_probs):
            hyp['probability'] = prob