'''
Created on 02-Mar-2021

@author: bthakur
'''
from xv.km.util._latex import latex_fraction
from xv.util import toIntOrFloat, to_non_sci_fmt, list_to_str, number_to_nth
from sympy import (Symbol, latex, Rational, simplify, nsimplify, sympify)
from sympy.core.expr import UnevaluatedExpr as ueval

'''
Created on 07-Feb-2021

@author: bthakur
'''
from functools import reduce
from ..util import MathUtil

import numpy as np
import random
import inspect
import traceback
from sympy import (
        simplify, sympify, symbols, Rational, oo, UnevaluatedExpr as ueval
    )


from ..helper import BaseHelper, PowerWalkHelper
from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate
from xv.km.util import wrap_in_latex

class PowerManager(BaseManager):
    '''
    Power or Exponent
    Example:
        ke = PowerManager()
        ke.printProblemTypes()

        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ke.getRandomProblem(problem_type = 1)
        ...
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()

        ke.initProblem(10, 24)
        ke.initProblem(15, 25, 30)

    '''
    def __new__(cls, *args, **kwargs):
        instance = super(PowerManager, cls).__new__(cls, *args, **kwargs)
        for base_class in PowerManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance

    def __init__(self, *args, **kwargs):
        self.base_helper = BaseHelper(**kwargs)
        pass


    def _init_data(self, b1 = None, exp_dict = None):
        if b1 is None:
            b1 = random.randint(2, 9)
        if exp_dict is None:
            e1, e2, e3, e4, e5 = random.sample(list(range(2, 10)), 5)
        else:
            e1 = exp_dict.get('e1', random.randint(2, 9))
            e2 = exp_dict.get('e2', random.randint(2, 9))
            e3 = exp_dict.get('e3', random.randint(2, 9))
            e4 = exp_dict.get('e4', random.randint(2, 9))
            e5 = exp_dict.get('e5', random.randint(2, 9))


        e1_large = random.randint(20, 100)
        b1_expr = " * ".join([str(b1) for x in range(e1)])
        b2_expr = " * ".join([str(b1) for x in range(e2)])
        b3_expr = " * ".join([str(b1) for x in range(e3)])
        b1_b2_expr = " * ".join([f"({b1_expr})" for x in range(e2)])

        return b1, e1, e2, e3, e4, e5, e1_large, b1_expr, b2_expr, b3_expr, b1_b2_expr

    def _init_prime_data(self):
        primes = [2, 3, 5, 7, 11, 13, 17]
        p1 = random.choice(primes)
        p2 = random.choice(primes)
        p3 = random.choice(primes)
        e1 = random.randint(2, 5)
        f1 = random.randint(2, 5)
        f2 = random.randint(2, 5)
        if f1%2 == 0:
            s1 = 1
        else:
            s1 = random.choice([1, -1])
            pass

        p1f1s1 = (p1* s1) ** f1

        return p1, p2, p3, e1, f1, f2, s1, p1f1s1

    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            '_problem_random_power_walk',
            '_problem_multiply',
            '_problem_concept_of_power',
            '_problem_express_as_power',
            '_problem_express_as_power_of_pairs',
            '_problem_express_as_power_as_large_series',
            '_problem_express_as_exp_of_base',
            '_problem_express_pair_as_exp_of_base',
            '_problem_exp_of_prod_div',
            '_problem_exp_of_prod_div_2',
            '_problem_exp_of_exp_pair',
            '_problem_exp_of_exp_pair_2',
            '_problem_exp_of_exp_pair_3',
            '_problem_exp_of_exp_pair_4',
            '_problem_exponent_to_root_form',
            '_problem_root_to_exponent_form',
            '_problem_expr_as_exp_of_primes',
            '_problem_expr_as_exp_of_primes_advanced',
            '_problem_exp_of_exp_pair_5',
            '_problem_exp_of_exp_pair_6',
            '_problem_exp_of_exp_pair_7',
            '_problem_exp_of_exp_pair_8',
            '_problem_exp_of_exp',
            '_problem_power_and_infinity',
            '_problem_power_zero',
            '_problem_power_negative',
            '_problem_express_negative_exp_as_rational_exp',
            '_problem_express_rational_exp_as_exp',
            '_problem_fractional_exp_of_exp',
            '_problem_exp_of_prime_4',
            '_problem_exp_solve_for_x_1',
            '_problem_exp_solve_for_x_2',
            '_problem_unit_digit_in_exp_number',
            '_problem_unit_digit_in_exp_expr',
         ])
        pass

    def _problem_random_power_walk(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        pwh = PowerWalkHelper(count = 10)

        start_s = f"Start at {pwh.walks[0].get('start_latex')}"
        problem_s = [start_s]
        soln_s = [start_s]
        answer_s = []

        for i, walk in enumerate(pwh.walks):
            p = f"{walk.get('statement')}"
            s = f"{walk.get('solution').strip()}"
            a = f"{walk.get('answer')}"
            problem_s.append(f"{i+1}. \t {p}")
            soln_s.append(f"{i+1}. \t {p} \n\n\n\t\t {s}")
            answer_s.append(f"{i+1}. \t {a}")
            pass

        problem_s = "\n\n".join(problem_s)
        soln_s = "\n\n\n".join(soln_s)
        answer_s = "\n\n".join(answer_s)

        problemTemplate.add_problem(f"""
        Use exponent or power to do the following:
        """, 'text/html')
        problemTemplate.add_problem(problem_s, 'text/html')

        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_multiply(self, *args, **kwargs):
        b1 = random.randint(2, 5)
        exp_dict = {'e1': random.randint(2, 5)}
        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data(b1, exp_dict = exp_dict)


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""Find value of
        ${b1_expr}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        ${b1_expr}$

        = ${b1**e1}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        ${b1**e1}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_concept_of_power(self, *args, **kwargs):

        (b01, e01, e02, e03, e04, e05, e01_large,
         b01_expr, b02_expr, b03_expr, b01_b02_expr )= self._init_data()

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        ${b01_expr}$ is written as ${b01}^{{{e01}}}$. What would you write for
        ${b1_expr}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        ${b1_expr}$

        = ${b1}^{{{e1}}}$

        The power is simply count of number of times a number is multipled.

        It is read as {b1} raised to the power {e1}.
        In short, {b1} power {e1}.

        {b1} is called base.
        {e1} has several names like power, exponent.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        ${b1}^{{{e1}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_express_as_power(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}
        ${b1_expr}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        ${b1_expr}$

        = ${b1}^{{{e1}}}$

        The power is simply count of number of times a number is multipled.

        It is read as {b1} raised to the power {e1}.
        In short, {b1} power {e1}.

        {b1} is called base.
        {e1} has several names like power, exponent.
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        ${b1}^{{{e1}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass

    def _problem_express_as_power_of_pairs(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()
        statement = f'Simplify as power of {b1}'
        expr = f"""({b1_expr}) * ({b2_expr})"""


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}
        ({b1_expr}) * ({b2_expr})
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        ({b1_expr}) * ({b2_expr})

        = ${b1}^{{{e1}}} * {b1}^{{{e2}}}$

        = ${b1}^{{{e1} + {e2}}}$

        = ${b1}^{{{e1 + e2}}}$

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        ${b1}^{{{e1 + e2}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

        pass

    def _problem_express_as_power_as_large_series(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Find value of
        {b1} * {b1} * {b1}  * .... {e1_large} times
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        {b1} * {b1} * {b1} * .... {e1_large} times

        = ${b1}^{{{e1_large}}}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        ${b1}^{{{e1_large}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_express_as_exp_of_base(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()
        b1_b2_expr_exponent = " * ".join([f"${b1}^{e1}$" for x in range(e2)])

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}

        {b1_b2_expr}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        {b1_b2_expr}

        = {b1_b2_expr_exponent}

        = ${b1}^{{{e1}  *  {e2}}}$

        = ${b1}^{{{e1 * e2}}}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        ${b1}^{{{e1 * e2}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_express_pair_as_exp_of_base(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        latex_fr_prob = latex_fraction(f"{b1_expr}",
                                       f"{b2_expr}"
                                       )

        latext_fr = latex_fraction(f"{b1}^{{{e1}}}", f"{b1}^{{{e2}}}")

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}

        $\\displaystyle {latex_fr_prob}$

        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle {latex_fr_prob}$

        $\\displaystyle = {latext_fr}$

        $\\displaystyle = {b1}^{{{e1} - {e2}}}$ \t\t As the numerator powers are added, denominator powers will be subtracted.

        $\\displaystyle = {b1}^{{{e1 - e2}}}$

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {b1}^{{{e1 - e2}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_exp_of_prod_div(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        latex_fr_prob = latex_fraction(f"{b2_expr}",
                                       f"{b3_expr}"
                                       )


        latex_fr = latex_fraction(f"{b1}^{{{e1}}} * {b1}^{{{e2}}}",
                                  f"{b1}^{{{e3}}}")

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}
        $\\displaystyle {b1_expr} * {latex_fr_prob}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle {b1_expr} * {latex_fr_prob}$

        $\\displaystyle = {latex_fr}$

        $\\displaystyle = {b1}^{{{e1} + {e2} - {e3}}}$

        $\\displaystyle = {b1}^{{{e1 + e2 - e3}}}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {b1}^{{{e1 + e2 - e3}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

        pass



    def _problem_exp_of_prod_div_2(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()
        statement = f'Simplify as power of {b1}'

        latex_fr_prob = latex_fraction(f"{b1_expr}",
                                  f"{b2_expr}")


        latex_fr = latex_fraction(f"{b1}^{{{e1}}}",
                                  f"{b1}^{{{e2}}}")


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}

        $\\displaystyle {latex_fr_prob} * {b3_expr}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle {latex_fr_prob} * {b3_expr}$

        $\\displaystyle = {latex_fr} * {b1}^{{{e3}}}$

        $\\displaystyle = {b1}^{{{e1} + {e3} - {e2}}}$

        $\\displaystyle = {b1}^{{{e1 + e3 - e2}}}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {b1}^{{{e1 + e3 - e2}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate


        pass

    def _problem_exp_of_exp(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}

        $({b1_expr})^{{{e3}}}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $({b1_expr})^{{{e3}}}$

        = $\\left({b1}^{{{e1}}}\\right)^{{{e3}}}$

        = ${b1}^{{{e1} * {e3}}}$

        = ${b1}^{{{e1 * e3}}}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        ${b1}^{{{e1 * e3}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

        pass


    def _problem_power_and_infinity(self, *args, **kwargs):

        import sympy as sp

        large_number = 10 ** 10 - 1
        small_large_number = 10 ** 3
        infinity_symb = Symbol(f'{latex(sp.oo)}')

        base_sign = random.choice([1, -1])
        exp_sign = random.choice([1, -1])


        b1_abs = random.choice([
            infinity_symb,
            0,
            random.randint(1, 9),
            Rational(random.randint(1, 9), random.randint(1, 9))
            ])

        b1 = b1_abs * base_sign

        e1_abs = infinity_symb
        e1 = e1_abs * exp_sign

        n1 = ueval(b1) ** ueval(e1)
        n1_val = f"\\text{{Undefined}}"

        n1_inv = ueval(b1) ** ueval(-e1)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        What is value of

        $\\displaystyle {latex(n1)}$

        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle {latex(infinity_symb)}$ is undefined. Hence,

        $\\displaystyle \\implies {latex(n1)} = {n1_val}$

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')


        if b1_abs == 1:
            soln_s = f"""
            However, if infinity is considered a very large number, say $\\displaystyle
            {latex(large_number)}$, it can be evaluated as

            $\\displaystyle

            {latex(n1)}

            = {latex(n1.subs(infinity_symb, large_number))}

            = {latex(n1.subs(infinity_symb, large_number).simplify())}
            $

            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')

        elif b1_abs == -1:
            large_plus_one = large_number + 1
            soln_s = f"""
            However, if infinity is considered a very large number, say $\\displaystyle
            {latex(large_number)}$, it can be evaluated as

            $\\displaystyle

            {latex(n1)}

            = {latex(n1.subs(infinity_symb, large_number))},
              {latex(n1.subs(infinity_symb, large_plus_one))}

            = {latex(n1.subs(infinity_symb, large_number).simplify())},
              {latex(n1.subs(infinity_symb, large_plus_one).simplify())}

            $

            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')

        elif b1_abs == 0 and exp_sign == -1:
            soln_s = f"""
            Also,

            $\\displaystyle
            {latex(n1)}
            = \\frac {{ 1 }} {{ {latex(n1_inv)} }}
            $

            As any number cannot be divided by zero, it is undefined.
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')

        elif b1_abs == 0:
            soln_s = f"""
            However, if infinity is considered a very large number, say $\\displaystyle
            {latex(large_number)}$, it can be evaluated as

            $\\displaystyle

            {latex(n1)}

            = {latex(n1.subs(infinity_symb, large_number))}

            = {latex(n1.subs(infinity_symb, large_number).simplify())}
            $

            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')

        elif (b1_abs != infinity_symb and
              exp_sign == -1 and
              n1.subs(infinity_symb, small_large_number).simplify() < 0.0001):

            if base_sign == -1:
                repl_symb = Symbol(f"\\pm {latex(infinity_symb)}")
                denm_symb = Symbol(f"\\text {{ Very large positive or negative number }}")
            else:
                repl_symb = infinity_symb
                denm_symb = Symbol(f"\\text {{ Very large positive number }}")

            soln_s = f"""
            However, if infinity is considered a very large number, say $\\displaystyle
            {latex(large_number)}$, it can be evaluated as

            $\\displaystyle

            {latex(n1)}

            = \\frac {{ 1 }} {{ {latex(n1_inv)} }}

            = \\frac {{ 1 }} {{ {latex(n1_inv.subs(infinity_symb, large_number))} }}

            = \\frac {{ 1 }} {{ {latex(denm_symb)} }}

            = 0

            $

            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')

        elif (b1_abs != infinity_symb and
              n1.subs(infinity_symb, small_large_number).simplify() > small_large_number):

            if base_sign == -1:
                calc_symb = Symbol(f"\\text {{ Very large positive or negative number }}")
            else:
                calc_symb = Symbol(f"\\text {{ Very large positive number }}")

            soln_s = f"""
            However, if infinity is considered a very large number, say $\\displaystyle
            {latex(large_number)}$, it can be evaluated as

            $\\displaystyle

            {latex(n1)}

            = {latex(n1.subs(infinity_symb, large_number))}

            = {latex(calc_symb)}

            = {latex(infinity_symb)}

            $

            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')

        elif (b1_abs != infinity_symb and
              n1.subs(infinity_symb, small_large_number).simplify() < 0.0001):

            if base_sign == -1:
                calc_symb = Symbol(f"\\text {{ Very small positive or negative number }}")
            else:
                calc_symb = Symbol(f"\\text {{ Very small positive number }}")

            soln_s = f"""
            However, if infinity is considered a very large number, say $\\displaystyle
            {latex(large_number)}$, it can be evaluated as

            $\\displaystyle

            {latex(n1)}

            = {latex(n1.subs(infinity_symb, large_number))}

            = {latex(calc_symb)}

            = 0

            $

            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')


        answer_s = f"""
        $\\displaystyle {n1_val}$

        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_power_zero(self, *args, **kwargs):

        b1 = random.choice([
            oo,
            0,
            random.randint(1, 9),
            Rational(random.randint(1, 9), random.randint(1, 9))
            ]) * random.choice([1, -1])

        e1 = 0

        b1_exp = ueval(b1) ** ueval(1)
        n1_raw = f"{{\\left({latex(b1)}\\right)}}^{{1-1}}"
        n1 = ueval(b1) ** ueval(e1)

        if b1 != 0 and b1 != oo and b1 != -oo:
            n1_val = sympify(1)
        else:
            n1_val = Symbol(f"\\text{{Undefined}}")


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        What is value of

        $\\displaystyle {latex(n1)}$

        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')


        soln_s = f"""
        $\\displaystyle
        \\begin{{aligned}}
        {latex(n1)}
        & = {n1_raw}
        \\qquad \\text {{ expressed power 0 as 1-1 }}
        \\\\ \\\\

        & = {latex_fraction(latex(b1_exp), latex(b1_exp))}
        \\qquad \\text {{ negative power can be expressed as denominator with positive power }}
        \\\\ \\\\

        & = {latex_fraction(latex(b1), latex(b1))}
        \\\\ \\\\

        & = {latex(n1_val)}

        \\end{{aligned}}
        $

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')


        answer_s = f"""
        $\\displaystyle {n1_val}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_power_negative(self, *args, **kwargs):

        b1 = random.choice([
            oo,
            0,
            random.randint(1, 9),
            Rational(random.randint(1, 9), random.randint(1, 9))
            ]) * random.choice([1, -1])

        e1 = - random.randint(1, 3)
        n1 = ueval(b1) ** ueval(e1)

        n1_pos = ueval(b1) ** ueval(-e1)
        n1_zero = f"{{\\left({latex(b1)}\\right)}}^{{0}}"

        n1_inv_expr3 = f"{{\\left({latex(b1)}\\right)}}^{{0 - {latex(abs(e1))}}}"
        n1_inv_expr2 = latex_fraction(n1_zero, latex(n1_pos))

        if b1 == 0 or b1 == oo or b1 == -oo:
            n1_inv_expr1 = n1_inv_expr2
        else:
            n1_inv_expr1 = latex_fraction(1, latex(n1_pos))


        if b1 != 0 and b1 != oo and b1 != -oo:
            n1_ueval = Symbol(f"{n1_inv_expr1}")
            n1_val = n1.simplify()
        else:
            n1_ueval = Symbol(f"\\text{{Undefined}}")
            n1_val = n1_ueval

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        What is value of

        $\\displaystyle {latex(n1)}$

        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_stmts = []

        soln_stmt = f"""
        $\\displaystyle
        \\begin{{aligned}}
        {latex(n1)}
        & = {n1_inv_expr3}
        \\qquad \\text {{ expressed power as }} 0 - {latex(abs(e1))}
        \\\\ \\\\

        & = {n1_inv_expr2}
        \\qquad \\text {{ negative power can be expressed as denominator with positive power }}
        \\\\ \\\\

        & = {n1_inv_expr1}
        \\\\ \\\\
        """
        soln_stmts.append(soln_stmt.strip())

        if n1_inv_expr1.replace(" ", "") != latex(n1_ueval).replace(" ", ""):
            soln_stmt = f"""
            & = {latex(n1_ueval)}
            \\\\ \\\\
            """
            soln_stmts.append(soln_stmt.strip())


        if latex(n1_ueval).replace(" ", "") != latex(n1_val).replace(" ", ""):
            soln_stmt = f"""
            & = {latex(n1_val)}
            \\\\ \\\\
            """
            soln_stmts.append(soln_stmt.strip())


        soln_stmt = f"""

        \\end{{aligned}}
        $

        """
        soln_stmts.append(soln_stmt.strip())


        soln_s = "\n\n".join(soln_stmts)

        problemTemplate.add_solution(soln_s.strip(), 'text/html')


        answer_s = f"""
        $\\displaystyle {latex(n1_val)}$

        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass

    def _problem_express_negative_exp_as_rational_exp(self, *args, **kwargs):

        b1 = random.randint(1, 9)
        e1_abs = random.randint(2, 5)
        e1 = - e1_abs
        b1_e1 = f"{b1}^{{{e1}}}"
        b1_e1_frac = latex_fraction(1, f"{b1}^{{{e1_abs}}}")

        soln_frac = latex_fraction(1, b1 ** e1_abs)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Express $\\displaystyle {b1_e1}$ as as rational number.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle {b1_e1}$

        The power becomes negative when we move it from numerator to denominator or from denominator to numerator
        $\\displaystyle = {b1_e1_frac}$

        $\\displaystyle = {soln_frac}$

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {soln_frac}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_express_rational_exp_as_exp(self, *args, **kwargs):

        b1 = random.randint(1, 9)
        e1_abs = random.randint(2, 5) * random.choice([1, -1])
        e1 = - e1_abs
        b1_e1 = f"{b1}^{{{e1}}}"
        b1_e1_frac = latex_fraction(1, f"{b1}^{{{e1_abs}}}")

        soln_frac = latex_fraction(1, b1 ** e1_abs)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Express $\\displaystyle {b1_e1_frac}$ as power of $\\displaystyle {b1}$.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle {b1_e1_frac}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        soln_s = f"""
        The power becomes negative when we move it from numerator to denominator or from denominator to numerator
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        if e1_abs < 0:
            soln_s = f"""
            $\\displaystyle = {b1}^{{-{e1_abs}}}$
            """
            problemTemplate.add_solution(soln_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle = {b1_e1}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        frc1 = latex_fraction(f"{b1}^0", f"{b1}^{{{e1_abs}}}")

        soln_s = f"""

        Alternatively:
        $\\displaystyle {b1_e1_frac}$

        $\\displaystyle = {frc1}$

        $\\displaystyle = {b1}^{{0 - {e1_abs}}} $

        $\\displaystyle = {b1_e1}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')



        answer_s = f"""
        $\\displaystyle {b1_e1}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass

    def _problem_fractional_exp_of_exp(self, *args, **kwargs):

        e1_inv = random.choice([
                random.randint(2, 5)
            ])
        exp_sign = random.choice([1, -1])
        e1 = Rational(1, e1_inv)
        e1_signed = e1 * exp_sign

        if random.choice([True, False]):
            float_precision = random.randint(1, 2)
            m1 = random.randint(1, 5) * 10 ** - float_precision
            if e1_inv % 2 != 0:
                m1 = m1 * random.choice([1, -1])

            b1 = toIntOrFloat(m1 ** e1_inv,
                              int(e1_inv * float_precision))
            pass
        else:
            m1 = random.choice([
                    random.randint(2, 9),
                    Rational(random.randint(1, 9), random.randint(2, 9)),
                ])
            if e1_inv % 2 != 0:
                m1 = m1 * random.choice([1, -1])

            if isinstance(m1, Rational):
                b1 = Rational(toIntOrFloat(m1.p ** e1_inv),
                              toIntOrFloat(m1.q ** e1_inv))
            else:
                b1 = int(m1 ** e1_inv)

            pass


        b1_raw = m1 ** ueval(e1_inv)

        n1_raw1 = b1 ** ueval(e1_signed)
        n1_raw2 = b1_raw ** ueval(e1_signed)
        n1_raw3 = f"\\left( {{{latex(m1)}}} \\right)^{{{latex(e1_inv)} * {latex(e1_signed)}}}"


        if isinstance(m1, float):
            n1_raw1_latex  = f"{{{to_non_sci_fmt(b1, e1_inv * float_precision)}}}^{{{latex(e1_signed)}}}"
        else:
            n1_raw1_latex  = latex(n1_raw1)

        n1_raw4 = f"\\left( {{{latex(m1)}}} \\right)^{{{exp_sign}}}"


        if exp_sign == -1:
            gross_answer_latex = latex_fraction(1, f"{latex(m1)}")
            answer = nsimplify(1/m1)
        else:
            gross_answer_latex = f"{latex(m1)}"
            answer = m1



        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify
        $\\displaystyle {n1_raw1_latex}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle {n1_raw1_latex}$

        $\\displaystyle = {latex(n1_raw2)}$

        $\\displaystyle = {n1_raw3}$

        $\\displaystyle = {n1_raw4}$

        $\\displaystyle = {gross_answer_latex}$

        $\\displaystyle = {latex(answer)}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {latex(answer)}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

        pass




    def _problem_exp_of_exp_pair(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}

        $\\displaystyle ({b1_expr})^{{{e3}}} \\cdot ({b2_expr})^{{{e4}}}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle ({b1_expr})^{{{e3}}} \\cdot ({b2_expr})^{{{e4}}}$

        $\\displaystyle  = {{ \\left({{{b1}}}^{{{e1}}}\\right) }}^{{{e3}}}
                    \\cdot {{ \\left({{{b1}}}^{{{e2}}}\\right) }}^{{{e4}}} $

        $\\displaystyle  = {{{b1}}}^{{{e1} * {e3}}} \\cdot {{{b1}}}^{{{e2} * {e4}}}$

        $\\displaystyle  = {{{b1}}}^{{{e1 * e3}}} \\cdot {{{b1}}}^{{{e2 * e4}}}$

        $\\displaystyle  = {{{b1}}}^{{{e1 * e3} + {e2 * e4}}}$

        $\\displaystyle  = {{{b1}}}^{{{e1 * e3 + e2 * e4}}}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {{{b1}}}^{{{e1 * e3 + e2 * e4}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

        pass


    def _problem_exp_of_exp_pair_2(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        latex_fr_prob = latex_fraction(f"({b1_expr})^{{{e3}}}",
                                       f"({b2_expr})^{{{e4}}}")


        latex_fr_soln1 = latex_fraction(f"{{ \\left({{{b1}}}^{{{e1}}}\\right) }}^{{{e3}}}",
                                        f"{{ \\left({{{b1}}}^{{{e2}}}\\right) }}^{{{e4}}}")

        latex_fr_soln2 = latex_fraction(f"{{{b1}}}^{{{e1} * {e3}}}",
                                        f"{{{b1}}}^{{{e2} * {e4}}}")

        latex_fr_soln3 = latex_fraction(f"{{{b1}}}^{{{e1 * e3}}}",
                                        f"{{{b1}}}^{{{e2 * e4}}}")


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}

        $\\displaystyle {latex_fr_prob}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle {latex_fr_prob}$

        $\\displaystyle = {latex_fr_soln1}$

        $\\displaystyle = {latex_fr_soln2}$

        $\\displaystyle = {latex_fr_soln3}$

        $\\displaystyle = {{{b1}}}^{{{e1 * e3} - {e2 * e4}}}$

        $\\displaystyle = {{{b1}}}^{{{e1 * e3 - e2 * e4}}}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {{{b1}}}^{{{e1 * e3 - e2 * e4}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_exp_of_exp_pair_3(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}

        $\\displaystyle {{ \\left({b1}^{{{e1}}}\\right) }}^{{{e3}}}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle {{ \\left({b1}^{{{e1}}}\\right) }}^{{{e3}}}$

        $\\displaystyle = {b1}^{{{e1} \\cdot {e3}}}$

        $\\displaystyle = {b1}^{{{e1 * e3}}}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""

        $\\displaystyle {b1}^{{{e1 * e3}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

        pass




    def _problem_exp_of_exp_pair_4(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}

        $\\displaystyle {{ \\left({b1}^{{{e1}}}\\right) }}^{{{latex_fraction(1 , e3, dfrac_latex = False)}}}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle {{ \\left(
        {b1}^{{{e1}}}\\right) }}^{{{latex_fraction(1 , e3, dfrac_latex = False)}}}$

        $\\displaystyle = {b1}^{{{e1} \\cdot {latex_fraction(1 , e3, dfrac_latex = False)}}}$

        $\\displaystyle = {b1}^{{{latex_fraction(e1 , e3, dfrac_latex = False)}}}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {b1}^{{{latex_fraction(e1 , e3, dfrac_latex = False)}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

        pass



    def _problem_expr_as_exp_of_primes(self, *args, **kwargs):

        p1, p2, p3, e1, f1, f2, s1, p1f1s1 = self._init_prime_data()
        if s1 < 1:
            p1s1 = f"\\left({p1 * s1}\\right)"
        else:
            p1s1 = p1 * s1

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Express as power of prime numbers:

        $\\displaystyle \\left({p1f1s1}\\right)^{{{e1}}}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle \\left({p1f1s1}\\right)^{{{e1}}}$

        $\\displaystyle = {{\\left({{{p1s1}}}^{f1}\\right)^{e1}}} $

        $\\displaystyle = {{\\left({{{p1s1}}}^{f1}\\right)^{e1}}} $

        $\\displaystyle = {{{p1s1}}}^{{ {f1} \\cdot {e1} }} $

        $\\displaystyle = {{{p1s1}}}^{{ {f1 * e1} }} $

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {{{p1s1}}}^{{ {f1 * e1} }} $
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

        pass


    def _problem_expr_as_exp_of_primes_advanced(self, *args, **kwargs):

        p1, p2, p3, e1, f1, f2, s1, p1f1s1 = self._init_prime_data()

        s1 = 1
        p1p2s1 = (p1 * p2) * s1

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Express as power of prime numbers

        $\\displaystyle \\left({p1p2s1}\\right)^{{{e1}}}$

        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle \\left({p1p2s1}\\right)^{{{e1}}}$

        $\\displaystyle = {{\\left({p1}*{p2}\\right)^{e1}}} $

        $\\displaystyle = {p1}^{e1} * {p2}^{e1} $
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {p1}^{e1} * {p2}^{e1} $
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_exponent_to_root_form(self, *args, **kwargs):
        pow_helper = self.base_helper.get_arithmetic_helper().get_power_helper()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')


        while True:
            root_base_p = random.randint(2, 5) * random.choice([1, -1])
            root_base_q = random.randint(2, 5)
            root_base_q = random.choice([1, root_base_q]) * random.choice([1, -1])
            root_base = Rational(root_base_p, root_base_q)
            if root_base != 1:
                break
            pass

        inv_root_base = Rational(root_base_q, root_base_p)

        while True:
            num_exp_p = random.randint(1, 5)
            num_exp_q = 1
            num_exp = Rational(num_exp_p, num_exp_q)
            if num_exp != 1:
                break
            pass

        num_base = random.randint(1, 9)
        num = num_base ** num_exp



        problem_s = f"""
        Convert the following into root form:
        $\\displaystyle {pow_helper.get_exp_latex(num, inv_root_base)}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s, answer_s = pow_helper.get_soln_exponent_to_root_form(num, root_base)

        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

        pass


    def _problem_root_to_exponent_form(self, *args, **kwargs):
        pow_helper = self.base_helper.get_arithmetic_helper().get_power_helper()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')


        while True:
            root_base_p = random.randint(2, 5) * random.choice([1, -1])
            root_base_q = random.randint(1, 5)
            root_base = Rational(root_base_p, root_base_q)
            if root_base != 1:
                break
            pass

        while True:
            num_exp_p = random.randint(1, 5)
            num_exp_q = 1
            num_exp = Rational(num_exp_p, num_exp_q)
            if num_exp != 1:
                break
            pass

        num_base = random.randint(1, 9)
        num = num_base ** num_exp

        problem_s = f"""
        Convert the following into exponential form:
        $\\displaystyle {pow_helper.get_nth_root_latex(root_base, num)}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s, answer_s = pow_helper.get_soln_root_to_exponent_form(num, root_base)

        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

        pass



    def _problem_exp_of_exp_pair_5(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}

        $\\displaystyle \\left({{ \\left({b1_expr}\\right)^{{{e3}}}
                 \\cdot \\left({b2_expr}\\right)^{{{e4}}}  }}\\right) ^{{{e5}}}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""

        $\\displaystyle \\left({{ \\left({b1_expr}\\right)^{{{e3}}}
                 \\cdot \\left({b2_expr}\\right)^{{{e4}}}  }}\\right) ^{{{e5}}}$

        $\\displaystyle = \\left({{ \\left({b1}^{{{e1}}}\\right)^{{{e3}}}
                   \\cdot \\left({b1}^{{{e2}}}\\right)^{{{e4}}}  }}\\right) ^{{{e5}}}$

        $\\displaystyle = \\left({b1}^{{{e1} * {e3}}}
                    \\cdot {b1}^{{{e2} * {e4}}}\\right) ^{{{e5}}}$

        $\\displaystyle = \\left({b1}^{{{e1 * e3}}}
                    \\cdot {b1}^{{{e2 * e4}}}\\right) ^{{{e5}}}$

        $\\displaystyle = {{ \\left({b1}^{{{e1 * e3} + {e2 * e4}}}\\right) }} ^ {{ {e5} }}$

        $\\displaystyle = {{ \\left({b1}^{{{e1 * e3 + e2 * e4}}}\\right) }} ^ {{ {e5} }}$

        $\\displaystyle = {b1}^{{{e1 * e3 + e2 * e4} * {e5}}}$

        $\\displaystyle = {b1}^{{{(e1 * e3 + e2 * e4) * e5}}}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle = {b1}^{{{(e1 * e3 + e2 * e4) * e5}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_exp_of_exp_pair_6(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        latex_fr_prob = latex_fraction(f"({b1_expr})^{{{e3}}}",
                                       f"({b2_expr})^{{{e4}}}")


        latex_fr_soln1 = latex_fraction(f"\\left({b1}^{{{e1}}}\\right)^{{{e3}}} ",
                                        f"\\left({b1}^{{{e2}}}\\right)^{{{e4}}}")

        latex_fr_soln2 = latex_fraction(f"{b1}^{{{e1} * {e3}}}",
                                        f"{b1}^{{{e2} * {e4}}}")

        latex_fr_soln3 = latex_fraction(f"{b1}^{{{e1 * e3}}}",
                                        f"{b1}^{{{e2 * e4}}}")

        problem_s = f"""
        Simplify as power of {b1}

        $\\displaystyle \\left({{ {latex_fr_prob}  }}\\right) ^{{{e5}}}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""

        $\\displaystyle \\left({{ {latex_fr_prob}  }}\\right) ^{{{e5}}}$

        $\\displaystyle = \\left({{ {latex_fr_soln1}  }}\\right) ^{{{e5}}}$

        $\\displaystyle = \\left({{ {latex_fr_soln2}  }}\\right) ^{{{e5}}}$

        $\\displaystyle = \\left({{ {latex_fr_soln3}  }}\\right) ^{{{e5}}}$

        $\\displaystyle = {{ \\left({b1}^{{{e1 * e3} - {e2 * e4}}}\\right) }} ^ {{ {e5} }}$

        $\\displaystyle = {{ \\left({b1}^{{{e1 * e3 - e2 * e4}}}\\right) }} ^ {{ {e5} }}$

        $\\displaystyle = {b1}^{{{e1 * e3 - e2 * e4} * {e5}}}$

        $\\displaystyle = {b1}^{{{(e1 * e3 - e2 * e4) * e5}}}$
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {b1}^{{{(e1 * e3 - e2 * e4) * e5}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass


    def _problem_exp_of_exp_pair_7(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}

        $\\displaystyle \\left({b1}^{{{e1}}}
                 \\cdot {b1}^{{{e2}}}\\right)^{{{e3}}}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle \\left({b1}^{{{e1}}}
                 \\cdot {b1}^{{{e2}}}\\right)^{{{e3}}}$

        $\\displaystyle = \\left({b1}^{{{e1} + {e2}}}\\right)^{{{e3}}}$

        $\\displaystyle = \\left({b1}^{{{e1 + e2}}}\\right)^{{{e3}}}$

        $\\displaystyle = {b1}^{{{e1 + e2} \\cdot {e3}}}$

        $\\displaystyle = {b1}^{{{(e1 + e2) * e3}}}$

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {b1}^{{{(e1 + e2) * e3}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass

    def _problem_exp_of_exp_pair_8(self, *args, **kwargs):

        (b1, e1, e2, e3, e4, e5, e1_large,
         b1_expr, b2_expr, b3_expr, b1_b2_expr )= self._init_data()

        latex_fr_prob = latex_fraction(f"{b1}^{{{e1}}}",
                                       f"{b1}^{{{e2}}}")


        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Simplify as power of {b1}

        $\\displaystyle \\left({latex_fr_prob}\\right)^{{{e3}}}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle \\left({latex_fr_prob}\\right)^{{{e3}}}$

        $\\displaystyle = \\left({b1}^{{{e1} - {e2}}}\\right)^{{{e3}}}$

        $\\displaystyle = \\left({b1}^{{{e1 - e2}}}\\right)^{{{e3}}}$

        $\\displaystyle = {b1}^{{{e1 - e2} * {e3}}}$

        $\\displaystyle = {b1}^{{{(e1 - e2) * e3}}}$

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {b1}^{{{(e1 - e2) * e3}}}$
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate
        pass



    def _problem_exp_of_prime_4(self, *args, **kwargs):
        p1, p2, p3, e1, f1, f2, s1, p1f1s1 = self._init_prime_data()
        p1f1p2f2 = (p1 ** f1) * (p2 ** f2)

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        Express as power of prime numbers

        ${p1f1p2f2}^{e1}$
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        $\\displaystyle {p1f1p2f2}^{e1}$

        $\\displaystyle = {{\\left({p1}^{f1} \\cdot {p2}^{f2}\\right)^{e1}}} $

        $\\displaystyle = {{\\left({p1}^{f1}\\right)^{e1}}}
                   \\cdot {{\\left({p2}^{f2}\\right)^{e1}}} $

        $\\displaystyle = {p1}^{{ {f1} * {e1} }}
                   \\cdot {p2}^{{ {f2} * {e1} }} $

        $\\displaystyle = {p1}^{{ {f1 * e1} }}
                   \\cdot {p2}^{{ {f2 * e1} }} $

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle {p1}^{{ {f1 * e1} }}
                 \\cdot {p2}^{{ {f2 * e1} }} $
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate


    def _problem_exp_solve_for_x_1(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        p1 = random.randint(2, 11)
        e1 = random.randint(2, 5)
        e2 = random.choice([e1, random.randint(2, 10)])

        x = symbols('x')
        statement = f"""Find value of {x}"""
        expr_s = f"""${x}^{{{e2}}} = {p1 ** e1} $"""

        problemTemplate.add_problem(statement)
        problemTemplate.add_problem(expr_s.strip(), 'latex/html')

        problemTemplate.add_solution(expr_s.strip(), 'latex/html')
        problemTemplate.add_solution(f"""$\\displaystyle \\implies {x}^{{{e2}}} = {p1}^{e1} $""",
                                     'text/html')
        problemTemplate.add_solution(f"""$\\displaystyle
        \\implies ({x}^{{{e2}}})^{{{1}/{e2}}} = ({p1}^{e1})^{{{1}/{e2}}} $""",
        'text/html')
        problemTemplate.add_solution(f"$\\displaystyle \\implies {x} = {p1}^{{{e1}/{e2}}}$",
                                     'text/html')

        if e1 == e2:
            answer_s = f"{p1}"
        else:
            answer_s = f"{p1}^{{{Rational(e1, e2)}}}"

        problemTemplate.add_solution(f"$\\displaystyle \\implies {x} = {answer_s}$", 'text/html')

        problemTemplate.add_answer(f"${x} = {answer_s}$", 'text/html')

        return problemTemplate

    def _problem_exp_solve_for_x_2(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        p1 = random.randint(2, 11)
        e1 = random.randint(2, 5)

        x = symbols('x')
        expr_s = f"""
        Find value of {x}
        ${p1}^{{{x}}} = {p1 ** e1} $
        """

        problemTemplate.add_problem(expr_s.strip(), 'text/html')

        problemTemplate.add_solution(expr_s.strip(), 'text/html')
        problemTemplate.add_solution(f"""$\\displaystyle \\implies {p1}^{{{x}}} = {p1}^{e1} $""",
                                     'text/html')

        problemTemplate.add_solution(f"$\\displaystyle \\implies {x} = {e1}$", 'text/html')

        problemTemplate.add_answer(e1, 'latex/html')

        return problemTemplate

    def _problem_unit_digit_in_exp_number(self, *args, **kwargs):

        power_helper = self.base_helper.get_arithmetic_helper().get_power_helper()

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        result = power_helper.get_unit_digit_of_an_exp_number()

        problem_s = f"""
        Find unit digit in {wrap_in_latex(result['num'])}.
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')


        soln_s = f"""
        {result['soln_s']}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        {result['answer_s']}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

    def _problem_unit_digit_in_exp_expr(self, *args, **kwargs):

        power_helper = self.base_helper.get_arithmetic_helper().get_power_helper()

        result_nums = []
        ops = []
        for i in range(random.randint(2, 5)):
            if i == 0:
                ops.append("")
            else:
                ops.append(random.choice(["+", "-", "*"]))

            result_nums.append(power_helper.get_unit_digit_of_an_exp_number())
            pass

        nums_latexes = [f"{ops[idx]} {latex(result_num['num'])}"
                        for idx, result_num in enumerate(result_nums)]
        nums_latexes_str = " ".join(nums_latexes)


        unit_digits_latexes = [f"""\\text{{ Unit digit of }} {latex(result_num['num'])}
                                = {latex(result_num['unit_digit'])}
                                """
                               for result_num in result_nums]

        unit_digits_latexes_str = " \\\\ ".join(unit_digits_latexes)


        last_digit_expr_terms = [f"{ops[idx]} {result_num['unit_digit']}"
                           for idx, result_num in enumerate(result_nums)]

        last_digit_expr = "".join(last_digit_expr_terms)
        last_digit_expr = sympify(last_digit_expr)

        last_digit_expr_latex = [f"{ops[idx]} {latex(result_num['unit_digit'])}"
                                 for idx, result_num in enumerate(result_nums)]

        last_digit_expr_latex_str = " ".join(last_digit_expr_latex)


        full_expr_terms = [f"{ops[idx]} {result_num['num']}"
                           for idx, result_num in enumerate(result_nums)]

        full_expr_terms = "".join(full_expr_terms)
        full_expr_terms = sympify(full_expr_terms)

        if full_expr_terms >= 0:
            expr_sign_stmt = " given that the expression is positive"
        else:
            expr_sign_stmt = " given that the expression is negative"

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')


        problem_s = f"""
        Find unit digit in the following expression {expr_sign_stmt}:

        $\\displaystyle
        {nums_latexes_str}
        $
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_stmts = []

        soln_stmt = f"""
        Unit digits of each term in the expression:

        $\\displaystyle
        {unit_digits_latexes_str}
        $

        Note: The detailed process of finding them is presented later in this solution.

        $\\displaystyle
        \\text{{The unit digit of }}
        \\left( {nums_latexes_str} \\right)
        $

        $\\displaystyle
        = \\text{{ The unit digit of }}
        \\left( {last_digit_expr_latex_str} \\right)
        $

        $\\displaystyle
        = \\text{{ The unit digit of }}
        \\left( {latex(last_digit_expr)} \\right)
        $

        """
        soln_stmts.append(soln_stmt.strip())

        if abs(last_digit_expr) > 10:
            expr_sign = last_digit_expr // abs(last_digit_expr)
            last_digit_expr = expr_sign * (abs(last_digit_expr) % 10)

            soln_stmt = f"""
            $\\displaystyle
            = \\text{{ The unit digit of }}
            \\left( {latex(last_digit_expr)} \\right)
            $
            """
            soln_stmts.append(soln_stmt.strip())
            pass


        if full_expr_terms >= 0 and last_digit_expr < 0:
            new_last_digit_expr = last_digit_expr + 10

            soln_stmt = f"""
            As the original given expression is positive,
            let us make the unit digit expression also positive
            by adding 10 to it.
            <br/>
            <br/>
            $\\displaystyle
            = \\text{{ The unit digit of }}
            \\left( {latex(last_digit_expr)} + 10 \\right)
            $
            <br/>
            <br/>
            $\\displaystyle
            = \\text{{ The unit digit of }}
            {latex(new_last_digit_expr)}
            $
            """
            soln_stmts.append(soln_stmt.replace("\n", " ").strip())
            last_digit_expr = new_last_digit_expr
            pass

        elif full_expr_terms < 0 and last_digit_expr >= 0:
            new_last_digit_expr = last_digit_expr - 10

            soln_stmt = f"""
            As the original given expression is negative,
            let us make the unit digit expression also negative
            by subtracting 10 from it.
            <br/>
            <br/>
            $\\displaystyle
            = \\text{{ The unit digit of }}
            \\left( {latex(last_digit_expr)} - 10 \\right)
            $
            <br/>
            <br/>
            $\\displaystyle
            = \\text{{ The unit digit of }}
            {latex(new_last_digit_expr)}
            $
            """
            soln_stmts.append(soln_stmt.replace("\n", " ").strip())

            last_digit_expr = new_last_digit_expr
            pass

        calc_unit_digit = str(last_digit_expr)[-1]
        soln_stmt = f"""
        $\\displaystyle \\implies
        \\text{{ The unit digit }}
        = {calc_unit_digit}
        $
        """
        soln_stmts.append(soln_stmt.strip())


        full_expr_str = str(full_expr_terms)
        real_last_digit = int(full_expr_str[-1])

        if len(full_expr_str) > 10:
            full_expr_str = f"{full_expr_str[:3]} \\cdots {full_expr_str[-3:]}"

        if real_last_digit != abs(last_digit_expr):
            soln_stmt = f"""
            Error: The correct unit digit should be:
            """
            soln_stmts.append(soln_stmt.strip())
        else:

            soln_stmt = f"""
            Verification of the result:
            """
            soln_stmts.append(soln_stmt.strip())
            pass

        soln_stmt = f"""
        $\\displaystyle
        \\text{{The unit digit of }}
        \\left(
        {nums_latexes_str}
        \\right)
        $

        $\\displaystyle
        = \\text{{The unit digit of }}
        \\left(
        {full_expr_str}
        \\right)
        $

        $\\displaystyle
        = {latex(real_last_digit)}
        $

        """
        soln_stmts.append(soln_stmt.strip())


        soln_stmt = f"""
        <h2>Detailed solution to find the last digit of each term</h2>
        """
        soln_stmts.append(soln_stmt.strip())

        for result_num in result_nums:
            soln_stmt = f"""
            {result_num['soln_s']}
            """
            soln_stmts.append(soln_stmt.strip())

        soln_s = "\n\n".join(soln_stmts)


        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        $\\displaystyle
        {latex(real_last_digit)}
        $
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

    def _sample(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

