Beispiel #1
0
class NumberParser:

    DIGITS = {
        'deux': 2,
        'trois': 3,
        'quatre': 4,
        'cinq': 5,
        'six': 6,
        'sept': 7,
        'huit': 8,
        'neuf': 9,
    }

    DIGITS_REVERSE = reverse_dict(DIGITS)

    NUMBERS = {
        'douze': 12,
        'treize': 13,
        'quatorze': 14,
        'quinze': 15,
        'seize': 16,
    }

    NUMBERS_REVERSE = reverse_dict(NUMBERS)

    # Verifier l'utilité de la distinction others / other_numbers
    OTHER_NUMBERS = {
        'zéro': 0,
        'un': 1,
        'onze': 11,
    }

    OTHERS = ['dix', 'onze', 'soixante', 'cent', 'mille']

    POWERS = {
        'mille': 3,
        'million': 6,
        'milliard': 9,
        'billion': 12,
        'billiard': 15,
        'trillion': 18,
        'trilliard': 21,
        'quadrillion': 24,
        'quadrilliard': 27,
        'quintillion': 30,
        'quintilliard': 33,
        'sextillion': 36,
        'sextilliard': 39,
        'septillion': 42,
        'septilliard': 45,
        'octillion': 48,
        'octilliard': 51,
        'nonillion': 54,
        'nonilliard': 57,
        'décillion': 60,
        'décilliard': 63,
    }

    POWERS_REVERSE = reverse_dict(POWERS)

    SAFE_DOZENS = {
        'vingt': 20,
        'trente': 30,
        'quarante': 40,
        'cinquante': 50,
        'septante': 70,
        'octante': 80,
        'nonante': 90,
    }

    DOZENS_REVERSE = {
        20: 'vingt',
        30: 'trente',
        40: 'quarante',
        50: 'cinquante',
        60: 'soixante',
        70: 'soixante',
        80: 'quatre vingt',
        90: 'quatre vingt'
    }

    COMMA = ['virgule', 'point']

    #il y a des redondances (pourquoi ?)
    NUMBER_WORDS = list(DIGITS.keys()) \
                   + list(NUMBERS.keys()) \
                   + list(OTHER_NUMBERS.keys()) \
                   + OTHERS \
                   + list(POWERS.keys()) \
                   + list(SAFE_DOZENS.keys()) \
                   + COMMA \
                   + ['et']

    AUTONOMOUS_NUMBER_WORDS = list(DIGITS.keys()) \
                              + list(NUMBERS.keys()) \
                              + list(OTHER_NUMBERS.keys()) \
                              + OTHERS \
                              + list(SAFE_DOZENS.keys())

    def __getattr__(self, p):
        if p == 'words':
            return self.words or []

    def _integer_parser(self):
        total_value = 0
        while self.words:
            value = self._integer_parser_lt1000()
            if value is not None and not self._end_of_parsed_integer():
                if self.words[0] in self.POWERS:
                    total_value += value * (10**self.POWERS[self.words[0]])
                    del self.words[0]
                    if self._end_of_parsed_integer():
                        return total_value
                else:
                    return total_value + value
            elif not self._end_of_parsed_integer() and \
                 self.words[0] == 'mille':
                total_value += 1000
                self.words = self.words[1:]
                if not self._end_of_parsed_integer():
                    value = self._integer_parser_lt1000()
                    return total_value + value
                return total_value
            elif value is not None:
                return total_value + value
            else:
                return None

    def number_parser(self, words, strict=False):
        self.words = _set_words(words)
        value = self._integer_parser()
        if value is None:
            return None
        if self.words:
            if self.words[0] in self.COMMA:
                del self.words[0]
                decimal = 0
                while True:
                    while self.words and self.words[0] == 'zero':
                        decimal += 1
                        del self.words[0]
                    comp = self._integer_parser()
                    if comp:
                        decimal += natural_log(comp) + 1
                        value += float(comp) / (10**decimal)
                    else:
                        break
        if not (strict and self.words):
            return value
        else:
            raise ValueError(
                '[strict=True] String %r does not represent any valid number.'
                % ''.join(words))

    def _end_of_parsed_integer(self):
        return (not self.words) or self.words[0] in self.COMMA

    def _integer_parser_60_80(self):
        if self.words[0] == 'soixante':
            self.words = self.words[1:]
            if len(self.words) > 1 and self.words[0] == 'et' and self.words[
                    1] in ['un', 'onze']:
                value = 60 + self.OTHER_NUMBERS[self.words[1]]
                del self.words[0]
                del self.words[0]
                return value
            elif not self._end_of_parsed_integer():
                value = self._integer_parser_lt20()
                if value:
                    return value + 60
            else:
                return 60
        elif len(self.words) > 1 and self.words[0] == 'quatre' and self.words[
                1] == 'vingt':
            self.words = self.words[2:]
            if self._end_of_parsed_integer():
                return 80
            elif self.words[0] in self.DIGITS:
                value = 80 + self.DIGITS[self.words[0]]
                self.words = self.words[1:]
                return value
            elif self.words[0] in ['un', 'onze']:
                value = 80 + self.OTHER_NUMBERS[self.words[0]]
                self.words = self.words[1:]
                return value
            elif self.words[0] in self.NUMBERS:
                value = 80 + self.NUMBERS[self.words[0]]
                self.words = self.words[1:]
                return value
            elif self.words[0] == 'dix':
                self.words = self.words[1:]
                if len(self.words) != 0 and self.words[0] in self.DIGITS:
                    value = 90 + self.DIGITS[self.words[0]]
                    del self.words[0]
                    return value
                return 90
        return None

    def _integer_parser_lt100(self):
        if self.words[0] in self.SAFE_DOZENS:
            value = self.SAFE_DOZENS[self.words[0]]
            del self.words[0]
            if not self._end_of_parsed_integer():
                if self.words[0] == 'et':
                    if len(self.words) > 1 and self.words[1] == 'un':
                        del self.words[0]
                        del self.words[0]
                        return value + 1
                elif self.words[0] in self.DIGITS:
                    value += self.DIGITS[self.words[0]]
                    del self.words[0]
            return value
        elif self.words[0] == 'soixante' or \
                (len (self.words) > 1 \
                 and self.words[0] == 'quatre' \
                 and self.words[1] == 'vingt'):
            return self._integer_parser_60_80()
        return self._integer_parser_lt20()

    def _integer_parser_lt1000(self):
        if self.words[0] == 'cent':
            self.words = self.words[1:]
            if self._end_of_parsed_integer():
                return 100
            value = self._integer_parser_lt100()
            if value:
                return 100 + value
            return None
        elif len(self.words) > 1 and self.words[1] == 'cent':
            try:
                value = 100 * self.DIGITS[self.words[0]]
                del self.words[0]
                del self.words[0]
                if not self._end_of_parsed_integer():
                    new_value = self._integer_parser_lt100()
                    if new_value:
                        return value + new_value
                return value
            except Exception:
                pass
        return self._integer_parser_lt100()

    def _integer_parser_lt20(self):
        if self.words[0] in self.DIGITS:
            value = self.DIGITS[self.words[0]]
            del self.words[0]
            return value
        if self.words[0] in self.OTHER_NUMBERS:
            value = self.OTHER_NUMBERS[self.words[0]]
            del self.words[0]
            return value
        if self.words[0] in self.NUMBERS:
            value = self.NUMBERS[self.words[0]]
            del self.words[0]
            return value
        if self.words[0] == 'dix':
            del self.words[0]
            value = 10
            if not self._end_of_parsed_integer():
                if self.words[0] in self.DIGITS:
                    value += self.DIGITS[self.words[0]]
                    del self.words[0]
            return value
        return None

    def _transcribe_lt99(self, n):
        l = []
        m = n // 10
        n %= dec(10)
        if m in [1, 7, 9]:
            if m != 1:
                l.append(self.DOZENS_REVERSE[int(10 * m)])
            if n == 0:
                l.append('dix')
            elif n == 1:
                if m == 7:
                    l.append('et')
                l.append('onze')
            elif n < 7:
                l.append(self.NUMBERS_REVERSE[int(10 + n)])
            else:
                l.append('dix')
                l.append(self.DIGITS_REVERSE[int(n)])
        else:
            if m > 1:
                l.append(self.DOZENS_REVERSE[int(10 * m)])
            if n == 1:
                if m not in [0, 8]:
                    l.append('et')
                l.append('un')
            elif n > 0:
                l.append(self.DIGITS_REVERSE[int(n)])
        return ' '.join(l)

    def _transcribe_lt999(self, n):
        if n == 0:
            return ''
        l = []
        m = n // dec(100)
        if m == 1:
            l.append('cent')
        elif m > 1:
            l.append(self.DIGITS_REVERSE[int(m)])
            l.append('cent')
        n %= dec(100)
        t = self._transcribe_lt99(n)
        if t:
            l.append(t)
        return ' '.join(l)

    def transcribe(self, n):
        l = []
        n = dec(n)
        if n < 1:
            l.append('zéro')
        else:
            i = natural_log(n)
            j = i // 3
            for k in range(j, 0, -1):
                m = n // 10**(3 * k)
                if m == 0:
                    continue
                p = self._transcribe_lt999(m)
                if p:
                    l.append(p)
                    l.append(self.POWERS_REVERSE[int(3 * k)])
                n %= dec(10**(3 * k))
            m = int(n)
            if m > 0:
                l.append(self._transcribe_lt999(m))
                n %= dec(1)
        if n > 0:
            l.append('virgule')
            while n != 0:
                n *= dec(10)
                m = int(n)
                if m == 0:
                    l.append('zéro')
                elif m == 1:
                    l.append('un')
                else:
                    l.append(self.DIGITS_REVERSE[int(m)])
                n %= dec(1)
        return ' '.join(l)

    def __call__(self, words, strict=False):
        return self.number_parser(words, strict=strict)
class UnaryOperatorConstructions(Construction):

    OPERATORS = {'NEG': {'latex': '-%s', 'priority': 4, 'nobrackets': False, 'postfix': False},
                 'SQR': {'latex': '\\sqrt{%s}', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 '3SQ': {'latex': '\\sqrt[3]{%s}', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'ABS': {'latex': '\\left| %s \\right|', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'FAC': {'latex': '%s!', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'CON': {'latex': '\\overline{%s}', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'FLO': {'latex': '\\lfloor %s \\rfloor', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'INV': {'latex': '%s^{-1}', 'priority': 5, 'nobrackets': True, 'postfix': True},
                 'STA': {'latex': '%s^{\star}', 'priority': 5, 'nobrackets': True, 'postfix': True},
                 'TIL': {'latex': '\\tilde{%s}', 'priority': 5, 'nobrackets': True, 'postfix': True},
                 'HAT': {'latex': '\\hat{%s}', 'priority': 5, 'nobrackets': True, 'postfix': True},
                 'DOT': {'latex': '\\dot{%s}', 'priority': 5, 'nobrackets': False, 'postfix': True},
                 'DDO': {'latex': '\\ddot{%s}', 'priority': 5, 'nobrackets': False, 'postfix': True},
                 'DDD': {'latex': '\\dddot{%s}', 'priority': 5, 'nobrackets': False, 'postfix': True},
                 'PRM': {'latex': '{%s}^\\prime', 'priority': 5, 'nobrackets': False, 'postfix': True},
                 'PPR': {'latex': '{%s}^{\\prime\\prime}', 'priority': 5, 'nobrackets': False, 'postfix': True},
                 'PPP': {'latex': '{%s}^{\\prime\\prime\\prime}', 'priority': 5, 'nobrackets': False, 'postfix': True},
                 'EXP': {'latex': '\\exp(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'LNN': {'latex': '\\ln(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'SIN': {'latex': '\\sin(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'COS': {'latex': '\\cos(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'TAN': {'latex': '\\tan(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'ARC': {'latex': '\\arccos(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'ARS': {'latex': '\\arcsin(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'ART': {'latex': '\\arctan(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'COH': {'latex': '\\cosh(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'SIH': {'latex': '\\sinh(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'TAH': {'latex': '\\tanh(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'KER': {'latex': '\\ker(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'IMA': {'latex': 'Im(%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'ITR': {'latex': '\\overset{\circ}{%s}', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'VSN': {'latex': '\\mathcal V (%s)', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'ADR': {'latex': '\\overline{%s}', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'FTR': {'latex': '\\partial %s ', 'priority': 5, 'nobrackets': True, 'postfix': False},
                 'NRM': {'latex': '\\Vert %s \\Vert','priority': 5, 'nobrackets': True, 'postfix': False},
                 'NRO': {'latex': '\\vvvert %s \\vvvert','priority': 5, 'nobrackets': True, 'postfix': False},
                 'EXI': {'latex': '\\exists %s ','priority': 5, 'nobrackets': True, 'postfix': False},
                 'EXU': {'latex': '\\exists ! %s ','priority': 5, 'nobrackets': True, 'postfix': False},
                 'QQS': {'latex': '\\forall %s ','priority': 5, 'nobrackets': True, 'postfix': False}
                 }

    OPERATORS_PARSED = {'moins': 'NEG',
                        'racine de': 'SQR',
                        'racine carré de': 'SQR',
                        'racine cubique de': '3SQ',
                        'valeur absolu de': 'ABS',
                        'factorielle de': 'FAC',
                        'conjugué de': 'CON',
                        'partie entière de': 'FLO',
                        'inverse de': 'INV',
                        'étoile': 'STA',
                        'tilde': 'TIL',
                        'chapeau': 'HAT',
                        'point': 'DOT',
                        'point point': 'DDO',
                        'point point point': 'DDD',
                        'prime': 'PRM',
                        'seconde': 'PPR',
                        'tierce': 'PPP',
                        'exponentielle de': 'EXP',
                        'logarithme népérien de': 'LNN',
                        'sinus de': 'SIN',
                        'cosinus de': 'COS',
                        'tangente de': 'TAN',
                        'arc cosinus de': 'ARC',
                        'arc sinus de': 'ARS',
                        'arc tangente de': 'ART',
                        'cosinus hyperbolique de': 'COH',
                        'sinus hyperbolique de': 'SIH',
                        'tangente hyperbolique de': 'TAH',
                        'noyau de': 'KER',
                        'image de': 'IMA',
                        'intérieur de': 'ITR',
                        'voisinage de': 'VSN',
                        'adhérence de': 'ADR',
                        'frontière de': 'FTR',
                        'norme de': 'NRM',
                        'norme subordonnée de': 'NRO',
                        'il existe': 'EXI',
                        'il existe un unique': 'EXU',
                        'quel que soit': 'QQS'}

    OPERATORS_REVERSE = reverse_dict(OPERATORS_PARSED)

    @classmethod
    def generate_help(cls):
        BLANK = '\\bullet'
        help = {}
        for (k, v) in cls.OPERATORS.items():
            n = cls.OPERATORS_REVERSE[k]
            help[n] = {'name': ' '.join(n.split(' ')[:(len(n)-1 or 1)]),
                       'latex': v['latex'] % BLANK,
                       'spelling': n,
                       'example': ('lambda %s' % n) if v['postfix'] else ('%s lambda' % n),
                       'example-latex': v['latex'] % '\\lambda'}
        return help
Beispiel #3
0
class BinaryOperatorConstructions(Construction):

    OPERATORS = {
        'EQU': {
            'latex': '%s = %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': True
        },
        'NEQ': {
            'latex': '%s \\neq %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'GEQ': {
            'latex': '%s \\geq %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'LEQ': {
            'latex': '%s \\leq %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'EQV': {
            'latex': '%s \\sim %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'SEQ': {
            'latex': '%s \\simeq %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'SBS': {
            'latex': '%s \\subset %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'SPS': {
            'latex': '%s \\supset %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'ADD': {
            'latex': '%s + %s',
            'priority': 1,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'SUB': {
            'latex': '%s - %s',
            'priority': 1,
            'associative': False,
            'weak': True,
            'nobrackets': False
        },
        'PMS': {
            'latex': '%s \\pm %s',
            'priority': 1,
            'associative': True,
            'weak': True,
            'nobrackets': False
        },
        'MPS': {
            'latex': '%s \\mp %s',
            'priority': 1,
            'associative': True,
            'weak': True,
            'nobrackets': False
        },
        'MUL': {
            'latex': '%s \\times %s',
            'priority': 2,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'DIV': {
            'latex': '\\frac{%s}{%s}',
            'priority': 2,
            'associative': False,
            'weak': False,
            'nobrackets': True
        },
        'CMP': {
            'latex': '%s \\circ %s',
            'priority': 2,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'VEC': {
            'latex': '%s \\wedge %s',
            'priority': 2,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'POW': {
            'latex': '{%s}^{%s}',
            'priority': 3,
            'associative': False,
            'weak': False,
            'nobrackets': False
        },
        'EVL': {
            'latex': '%s \\left( %s \\right)',
            'priority': 4,
            'associative': False,
            'weak': False,
            'nobrackets': True
        },
        'BIN': {
            'latex': '\\binom {%s} {%s}',
            'priority': 4,
            'associative': False,
            'weak': False,
            'nobrackets': True
        },
        'BEL': {
            'latex': '%s \\in %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'NBL': {
            'latex': '%s \\notin %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'PRI': {
            'latex': '%s \\setminus %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'UNI': {
            'latex': '%s \\cup %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'INT': {
            'latex': '%s \\cap %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'SYM': {
            'latex': '%s \\oplus %s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'DST': {
            'latex': 'd ( %s , %s )',
            'priority': 0,
            'associative': False,
            'weak': False,
            'nobrackets': True
        },
        'BLO': {
            'latex': 'B ( %s , %s )',
            'priority': 0,
            'associative': False,
            'weak': False,
            'nobrackets': True
        },
        'BLF': {
            'latex': 'B_f ( %s , %s )',
            'priority': 0,
            'associative': False,
            'weak': False,
            'nobrackets': True
        },
        'DVS': {
            'latex': '%s \\mid  %s',
            'priority': 0,
            'associative': False,
            'weak': False,
            'nobrackets': True
        },
        'NDV': {
            'latex': '%s \\nmid %s',
            'priority': 0,
            'associative': False,
            'weak': False,
            'nobrackets': True
        },
        'MOD': {
            'latex': '%s \\pmod{%s} ',
            'priority': 0,
            'associative': False,
            'weak': False,
            'nobrackets': True
        },
        'CGR': {
            'latex': '%s \\equiv %s ',
            'priority': 0,
            'associative': False,
            'weak': False,
            'nobrackets': True
        },
        'GCD': {
            'latex': '%s \\wedge %s ',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': True
        },
        'LCM': {
            'latex': '%s \\vee %s ',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': True
        },
        'IDX': {
            'latex': '{%s}_{%s}',
            'priority': 4,
            'associative': False,
            'weak': False,
            'nobrackets': False
        },
        'CMA': {
            'latex': '%s,%s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'SCN': {
            'latex': '%s;%s',
            'priority': 0,
            'associative': True,
            'weak': False,
            'nobrackets': False
        },
        'PIR': {
            'latex': '\\left( %s, %s \\right)',
            'priority': 0,
            'associative': False,
            'weak': False,
            'nobrackets': True
        },
    }

    OPERATORS_PARSED = {
        'plus': 'ADD',
        'moins': 'SUB',
        'fois': 'MUL',
        'sur': 'DIV',
        'divisé par': 'DIV',
        'puissance': 'POW',
        'égal': 'EQU',
        'différent de': 'NEQ',
        'supérieur à': 'GEQ',
        'inférieur à': 'LEQ',
        'plus ou moins': 'PMS',
        'moins ou plus': 'MPS',
        'rond': 'CMP',
        'vectoriel': 'VEC',
        'inclus dans': 'SBS',
        'contient': 'SPS',
        'équivaut à': 'EQV',
        'environ égal à': 'SEQ',
        'de': 'EVL',
        'binomial': 'BIN',
        'appartient à': 'BEL',
        "nappartient pas à": 'NBL',
        'privé de': 'PRI',
        'union': 'UNI',
        'intersection': 'INT',
        'différence symétrique': 'SYM',
        'distance': 'DST',
        'boule ouverte': 'BLO',
        'boule fermée': 'BLF',
        'divise': 'DVS',
        'ne divise pas': '******',
        'modulo': 'MOD',
        'congru à': 'CGR',
        'pgcd': 'GCD',
        'ppcm': 'LCM',
        'indice': 'IDX',
        'virgule': 'CMA',
        'point virgule': 'SCN',
        'paire': 'PIR',
    }

    OPERATORS_REVERSE = reverse_dict(OPERATORS_PARSED)

    @classmethod
    def generate_help(cls):
        BLANK = ('\\bullet', '\\bullet')
        help = {}
        for (k, v) in cls.OPERATORS.items():
            n = cls.OPERATORS_REVERSE[k]
            help[n] = {
                'name': n,
                'latex': v['latex'] % BLANK,
                'spelling': n,
                'example': 'lambda %s mu' % n,
                'example-latex': v['latex'] % ('\\lambda', '\\mu')
            }
        return help
Beispiel #4
0
class BigOperatorConstructions(Construction):

    OPERATORS = {'ITG': {'latex': '\\int_{%s}^{%s} %s', 'priority': 1, 'type': 'SUM', 'subtype': 'CON'},
                 'SUM': {'latex': '\\sum_{%s}^{%s} %s', 'priority': 1, 'type': 'SUM', 'subtype': 'DIS'},
                 'PRO': {'latex': '\\prod_{%s}^{%s} %s', 'priority': 2, 'type': 'SUM', 'subtype': 'DIS'},
                 'ITR': {'latex': '\bigcap_{%s}^{%s} %s', 'priority': 2, 'type': 'SUM', 'subtype': 'DIS'},
                 'UNI': {'latex': '\bigcup_{%s}^{%s} %s', 'priority': 1, 'type': 'SUM', 'subtype': 'DIS'},
                 'LIM': {'latex': '\\underset{ %s \\rightarrow \%s}{\\lim} %s ', 'priority': 1, 'type': 'LIM', 'subtype': 'LIM'},
                 'ITR': {'latex': '%s%s,%s%s', 'priority': 3, 'type': 'ITV', 'subtype': 'ITV'},
                 'ITI': {'latex': '%s%s,%s%s', 'priority': 3, 'type': 'ITV', 'subtype': 'ITV'},
                 'DER': {'latex': '\\mathrm{d}_{%s}^{%s} %s', 'priority': 5, 'type': 'DEV', 'subtype': 'DEV'},
                 'PAR': {'latex': '\\partial_{%s}^{%s} %s', 'priority': 5, 'type': 'DEV', 'subtype': 'DEV'},
                 }

    OPERATORS_PARSED = {'intégrale': 'ITG',
                        'somme': 'SUM',
                        'produit': 'PRO',
                        'intersection': 'ITR',
                        'union': 'UNI',
                        'limite': 'LIM',
                        'intervalle': 'ITR',
                        'intervalle entier': 'ITI',
                        'dé': 'DER',
                        'dé rond': 'PAR',
                        }

    OPERATORS_REVERSE = reverse_dict(OPERATORS_PARSED)

    BOUNDS = {('ITR', 'OP', 0): '\\left]',
              ('ITR', 'CL', 0): '\\left[',
              ('ITR', 'OP', 1): '\\right[',
              ('ITR', 'CL', 1): '\\right]',
              ('ITI', 'OP', 0): '\\left]\\!\\left]',
              ('ITI', 'CL', 0): '\\left[\\!\\left[',
              ('ITI', 'OP', 1): '\\right[\\!\\right[',
              ('ITI', 'CL', 1): '\\right]\\!\\right]',}

    BOUNDS_PARSED = {'ouvert': 'OP',
                     'fermé': 'CL'}

    BOUNDS_REVERSE = reverse_dict(BOUNDS_PARSED)

    @classmethod
    def generate_help(cls):
        BLANK = ('\\bullet', '\\bullet', '\\bullet')
        help = {}
        for (k, v) in cls.OPERATORS.items():
            n = cls.OPERATORS_REVERSE[k]
            if v['type'] == 'SUM':
                if v['subtype'] == 'CON':
                    help[n] = {'name': n,
                               'latex': v['latex'] % BLANK,
                               'spelling': n,
                               'example': '%s de un à deux de lambda au carré' % n,
                               'example-latex': v['latex'] % ('1', '2', '\\lambda^2')}
                elif v['subtype'] == 'DIS':
                    help[n] = {'name': n,
                               'latex': v['latex'] % BLANK,
                               'spelling': n,
                               'example': '%s pour lambda égal un à dix de lambda au carré' % n,
                               'example-latex': v['latex'] % ('\\lambda=1', '10', '\\lambda^2')}
            if v['type'] == 'LIM':
                if v['subtype'] == 'LIM':
                    help[n] = {'name': n,
                               'latex': v['latex'] % BLANK,
                               'spelling': n,
                               'example': '%s quand n tend vers l\'infini de u de n' % n,
                               'example-latex': v['latex'] % ('n', '\\infty', 'u_n')}
            if v['type'] == 'ITV':
                if v['subtype'] == 'ITV':
                    help[n] = {'name': n,
                               'latex': v['latex'] % ('\\bullet', '\\bullet', '\\bullet', '\\bullet'),
                               'spelling': n,
                               'example': '%s fermé en 1 ouvert en 2' % n,
                               'example-latex': v['latex'] % ('\\left[', '1', '2', '\\right[')}
            if v['type'] == 'DEV':
                if v['subtype'] == 'DEV':
                    help[n] = {'name': n,
                               'latex': v['latex'] % BLANK,
                               'spelling': n,
                               'example': '%s par rapport à lambda puissance deux de mu' % n,
                               'example-latex': v['latex'] % ('\\lambda', '2', '\\mu')}

        return help
class VariableConstructions(Construction):

    RADIO_ROMAN_PARSED = {
        'alpha': 'a',
        'bravo': 'b',
        'charlie': 'c',
        'delta': 'd',
        'echo': 'e',
        'foxtrot': 'f',
        'golf': 'g',
        'hotel': 'h',
        'india': 'i',
        'juliet': 'j',
        'kilo': 'k',
        'lima': 'l',
        'mike': 'm',
        'november': 'n',
        'oscar': 'o',
        'papa': 'p',
        'québec': 'q',
        'romeo': 'r',
        'sierra': 's',
        'tango': 't',
        'uniform': 'u',
        'victor': 'v',
        'whisky': 'w',
        'xray': 'x',
        'yankee': 'y',
        'zulu': 'z'
    }

    RADIO_ROMAN_REVERSE = reverse_dict(RADIO_ROMAN_PARSED)

    GREEK_PARSED = {
        'alpha grec': '\\alpha',
        'beta': '\\beta',
        'gamma': '\\gamma',
        'delta grec': '\\delta',
        'epsilon': '\\varepsilon',
        'epsilon variante': '\\varepsilon',
        'zeta': '\\zeta',
        'eta': '\\eta',
        'theta': '\\theta',
        'theta variante': '\\vartheta',
        'iota': '\\iota',
        'kappa': '\\kappa',
        'lambda': '\\lambda',
        'mu': '\\mu',
        'nu': '\\nu',
        'xi': '\\xi',
        'pi': '\\pi',
        'pi variante': '\\varpi',
        'rho': '\\rho',
        'rho variante': '\\varrho',
        'sigma': '\\sigma',
        'sigma variante': '\\varsigma',
        'tau': '\\tau',
        'upsilon': '\\upsilon',
        'phi': '\\phi',
        'phi variante': '\\varphi',
        'chi': '\\chi',
        'psi': '\\psi',
        'omega': '\\omega',
        'gamma majuscule': '\\Gamma',
        'gamma majuscule variante': '\\varGamma',
        'delta majuscule': '\\Delta',
        'delta majuscule variante': '\\varDelta',
        'theta majuscule': '\\Theta',
        'theta majuscule variante': '\\varTheta',
        'lambda majuscule': '\\Lambda',
        'lambda majuscule variante': '\\varLambda',
        'xi majuscule': '\\Xi',
        'xi majuscule variante': '\\varXi',
        'pi majuscule': '\\Pi',
        'pi majuscule variante': '\\varPi',
        'sigma majuscule': '\\Sigma',
        'sigma majuscule variante': '\\varSigma',
        'upsilon majuscule': '\\Upsilon',
        'upsilon majuscule variante': '\\varUpsilon',
        'phi majuscule': '\\Phi',
        'phi majuscule variante': '\\varPhi',
        'psi majuscule': '\\Psi',
        'psi majuscule variante': '\\varPsi',
        'omega majuscule': '\\Omega',
        'omega majuscule variante': '\\varOmega',
    }

    GREEK_REVERSE = reverse_dict(GREEK_PARSED)

    SET_PARSED = {
        'grand r': '\\mathbb{R}',
        'grand q': '\\mathbb{Q}',
        'grand z': '\\mathbb{Z}',
        'grand n': '\\mathbb{N}',
        'grand d': '\\mathbb{D}',
        'grand p': '\\mathbb{P}',
    }

    SET_REVERSE = reverse_dict(SET_PARSED)

    @classmethod
    def generate_help(cls):
        help = {}
        for (k, v) in cls.RADIO_ROMAN_PARSED.items():
            help[v] = {
                'name': v,
                'latex': v,
                'spelling': k,
                'example': k,
                'example-latex': v
            }
        for (k, v) in cls.GREEK_PARSED.items():
            help[k] = {
                'name': k,
                'latex': v,
                'spelling': k,
                'example': k,
                'example-latex': v
            }
        for (k, v) in cls.SET_PARSED.items():
            help[k] = {
                'name': k,
                'latex': v,
                'spelling': k,
                'example': k,
                'example-latex': v
            }
        return help