
class Tagger:

    def local_score( self, prevtag, tag, words, i ):
        features = self.featureVec(prevtag, tag, words, i)
        return math.exp(sum(self.weight[f] * v for f, v in features))
    
    def forward(self, words):
        # Initialisierung der Forward-Tabelle
        fwd_prob = [defaultdict(float) for _ in words]
        fwd_prob[0]['<s>'] = 1.0
        for i in range(1, len(words)):
            tags = tagset if i < len(words)-1 else ['<s>']
            for tag2 in tags:
                for tag1, prevp in fwd_prob[i-1].items():
                    p = prevp * self.local_score(tag1, tag2, words, i)
                    fwd_prob[i][tag2] += p
        return fwd_prob
    
    def backward(self, words):
        # Initialisierung der Forward-Tabelle
        bwd_prob = [defaultdict(float) for _ in words]
        bwd_prob[-1]['<s>'] = 1.0
        for i in range(len(words)-1, 0, -1):
            tags = tagset if i > 1 else ['<s>']
            for tag1 in tags:
                for tag2, nextp in bwd_prob[i].items():
                    p = nextp * self.local_score(tag1, tag2, words, i)
                    bwd_prob[i-1][tag1] += p
        return bwd_prob
    
    def EStep(self, words, estFeatValue):
        words =  [''] + words + ['', '']  # Grenztokens hinzufügen
        fwd_prob = self.forward(words)
        bwd_prob = self.backward(words)
        totalp = fwd_prob[-1]['<s>']
        for i in range(1, len(words)):
            tags = tagset if i < len(words)-1 else ['<s>']
            for tag2, nextp in bwd_prob[i].items():
                for tag1, prevp in fwd_prob[i-1].items():
                    p = prevp * self.local_score(tag1, tag2, words, i) * nextp / totalp
		    features = self.featureVec(tag1, tag2, words, i)
		    for f, v in features:
                        estFeatValue[f] += p * v

