'''
Created on 20-Jan-2022

@author: bthakur
'''

import codecs
import inspect
import traceback
import random
import numpy as np


import sympy as sp 

from sympy import (latex, Symbol, symbols,
                   Matrix, Identity, nsimplify, sympify,
                    Rational,
                    sin, cos, tan,
                    asin, acos, atan,
                    sinh, cosh, tanh,
                    log, exp, sqrt,
                   diff, factor, 
                   Function, Eq,
                   Add, 
                   simplify, solve, factorial,
                   Derivative,
                   UnevaluatedExpr as ueval,
                   
                   
                   )
from sympy.core.numbers import One, Integer
from sympy.series import series

from xv.km.util import latex_fraction


from xv.km.ui import SvgHelper
from xv.util.data import CacheUtil

import matplotlib.pyplot as plt
from xv.util import CategorizedSampleData, list_to_str

# _laplace_transform_helper
# LaplaceTransformHelper


from xv.util import UtilClass

class LaplaceTransformHelper(UtilClass):
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        
        pass
    
    def get_problem_overview_laplace_transform(self, **kwargs):
        '''
        '''
        sInfo = f"""Processing {self.__class__.__name__}.{inspect.stack()[0][3]}: """
        self._log(sInfo.strip())

        index = kwargs.get('index', None)
        
        try:
            
            if index is None:
                random_choices = list(range(1, 9))
        
                identifier = f"{self.__class__.__name__}{id(self)}.{inspect.stack()[0][3]}.random_choices"
                random_choice = self.get_no_repeat_random_choice(identifier, random_choices)
            else:
                random_choice = index
            
            if random_choice == 1:
                return self._problem_laplace_transform_overview()
            
            
            return self._problem_laplace_transform_overview()
        
        except Exception as e:
            sError = f"""Error {self.__class__.__name__}.{inspect.stack()[0][3]}: {e}
            """
            self._log(sError)
            self._log(traceback.format_exc())
            pass
        
        return None
        pass

    def _problem_laplace_transform_overview(self, **kwargs):
        
         
        prob_s = f"""
        Define gamma function 
        """
        
        soln_stmts = []
        z = Symbol('z', complex = True)
        Gamma = Function('Gamma')(z)
        
        t = Symbol('t')
        Gamma_expr = t**(z - 1) * sp.exp(-t)
        Gamma_func_expr = sp.Integral(Gamma_expr, (t, 0, sp.oo))
        
        soln_stmt = f"""
        The gamma function ${latex(Gamma)}$ is a complex function that extends the concept of
        factorials to real and complex numbers. It is defined for all complex
        numbers ${latex(z)}$ except for non-positive integers. The gamma function is given
        by the following integral for complex numbers with a positive real part:

        """
        soln_stmts.append(soln_stmt.replace('\n', ' ').strip())
        
        soln_stmt = f"""
        $\\displaystyle
        {latex(Gamma)} = {latex(Gamma_func_expr)}
        $
        """
        soln_stmts.append(soln_stmt.strip())
        
        
        soln_stmt = f"""
 
        """
        soln_stmts.append(soln_stmt.strip())

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

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

        answer_s = f"""
        $\\displaystyle
        {latex(Gamma)} = {latex(Gamma_func_expr)}
        $
        """
        
        soln_s = "\n\n".join(soln_stmts)
        
                
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        
        return result
        pass
    
    def _problem_proof_laplace_transform(self, **kwargs):
        z = Symbol('z', complex = True, constant = True)
        Gamma = Function('Gamma')(z)
        Gamma_1 = Function('Gamma')(z + 1)
        
        prob_s = f"""
        Prove that $\\displaystyle {latex(Gamma_1)} = {latex(z * Gamma)}$ for ${latex(sp.StrictGreaterThan(z, 1))}$
        """
        
        soln_stmts = []
        
        soln_stmt = f"""
        
        """
        soln_stmts.append(soln_stmt.replace('\n', ' ').strip())
        
        
        t = Symbol('t')
        Gamma_expr = t**(z - 1) * sp.exp(-t)
        Gamma_func_expr = sp.Integral(Gamma_expr, (t, 0, sp.oo))

        Gamma_1_expr = Gamma_expr.subs(z, z + 1)
        Gamma_1_func_expr = sp.Integral(Gamma_1_expr, (t, 0, sp.oo))
        Gamma_1_func_expr_inte_by_parts_p1_symb = Symbol('\\left[ - t^z e^{-t} \\right]_{0}^{\\infty}')
        Gamma_1_func_expr_inte_by_parts_p1 = (Gamma_1_expr.subs(t, sp.oo) - Gamma_1_expr.subs(t, 0)).simplify(force = True)
        Gamma_1_func_expr_inte_by_parts_p2 = sp.Integral(t**(z - 1) *sp.exp(-t), (t, 0, sp.oo))
        Gamma_1_func_expr_simplified = z * Gamma_1_func_expr_inte_by_parts_p2
        
        soln_stmt = f"""
        $\\displaystyle
        \\begin{{aligned}}
        {latex(Gamma)} &= {latex(Gamma_func_expr)} \\\\
        {latex(Gamma_1)} &= {latex(Gamma_1_func_expr)} \\\\
        &= {latex(Gamma_1_func_expr_inte_by_parts_p1_symb)} + {latex(z * Gamma_1_func_expr_inte_by_parts_p2)} \\\\
        &= {latex(Gamma_1_expr.subs(t, sp.oo))} - {latex(Gamma_1_expr.subs(t, 0))} + {latex(z * Gamma_1_func_expr_inte_by_parts_p2)} \\\\
        &= {latex(Gamma_1_func_expr_inte_by_parts_p1)} + {latex(z * Gamma_1_func_expr_inte_by_parts_p2)} \\\\
        &= {latex(Gamma_1_func_expr_simplified)} \\\\
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())
        
        soln_stmt = f"""
        We know that $\\displaystyle {latex(Gamma)} = {latex(Gamma_func_expr)}$
        $\\displaystyle
        \\begin{{aligned}}
        {latex(Gamma_1)} &= {latex(Gamma_1_func_expr_simplified)} \\\\
        {latex(Gamma_1)} &= {latex(Gamma_1_func_expr_simplified.subs(Gamma_func_expr, Gamma))} \\\\
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())

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

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

        answer_s = f"""
        
        """
        
        soln_s = "\n\n".join(soln_stmts)
        
                
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        
        return result
        pass

    def _problem_solve_laplace_transform_of_an_integer(self, **kwargs):
        z = Symbol('z', complex = True, constant = True)
        Gamma = Function('Gamma')(z)
        Gamma_1 = Function('Gamma')(z + 1)
        random_int = random.randint(2, 6)
        prob_s = f"""
        Solve $\\displaystyle {latex(Gamma)}$ for ${latex(Eq(z, random_int))}$
        """
        
        soln_stmts = []
        
        soln_stmt = f"""
        
        """
        soln_stmts.append(soln_stmt.replace('\n', ' ').strip())
        
        
        Gamma_1_expr = z * Gamma

        
        soln_stmt = f"""
        $\\displaystyle
        \\begin{{aligned}}
        & {latex(Gamma_1)} = {latex(Gamma_1_expr)} \\\\
        \\Rightarrow & {latex(Gamma_1.subs(z, z - 1))} = {latex(Gamma_1_expr.subs(z, z - 1))} \\\\
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())

        for idx in range(random_int, 1, -1):
            if idx == random_int:
                latex_str = ''
            latex_str = latex_str + f" &= {latex(sp.Mul(*list(range(random_int - 1, idx - 2, -1))))} {latex(Gamma.subs(z, idx - 1))} \\\\" + '\n'

        soln_stmt = f"""
        For ${latex(Eq(z, random_int))}$
        $\\displaystyle
        \\begin{{aligned}}
        {latex(Gamma.subs(z, random_int))} {latex_str} \\\\
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())

        
        soln_stmt = f"""
        We can replace ${latex(Eq(Gamma.subs(z, 1), 1))}$ 
        $\\displaystyle
        \\begin{{aligned}}
        {latex(Gamma.subs(z, random_int))} &= {latex(sp.Mul(*list(range(random_int - 1, 1, -1))))} {latex(Gamma.subs(z, 1))} \\\\ 
        &= {latex(sp.Mul(*list(range(random_int - 1, 1, -1))))}
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())

        answer_s = f"""
        $\\displaystyle
        \\begin{{aligned}}
        {latex(Gamma.subs(z, random_int))} &= {latex(sp.Mul(*list(range(random_int - 1, 1, -1))))}
        \\end{{aligned}}
        $
        """
        
        soln_s = "\n\n".join(soln_stmts)
        
                
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        
        return result
        pass
    
    def _problem_solve_laplace_transform_of_1(self, **kwargs):
        z = Symbol('z', complex = True, constant = True)
        Gamma = Function('Gamma')(z)
        
        
        prob_s = f"""
        Solve for $\\displaystyle {latex(Gamma)}$ for ${latex(Eq(z, 1))}$
        """
        
        soln_stmts = []
        
        soln_stmt = f"""
        
        """
        soln_stmts.append(soln_stmt.replace('\n', ' ').strip())
        
        t = Symbol('t')
        Gamma_expr = t**(z - 1) * sp.exp(-t)
        Gamma_func_expr = sp.Integral(Gamma_expr, (t, 0, sp.oo))
        
        soln_stmt = f"""
        $\\displaystyle
        \\begin{{aligned}}
        & {latex(Gamma)} = {latex(Gamma_func_expr)} \\\\
        \\Rightarrow & {latex(Gamma.subs(z, 1))} = {latex(Gamma_func_expr.subs(z, 1))} \\\\
        \\Rightarrow & {latex(Gamma.subs(z, 1))} = {latex(Gamma_func_expr.subs(z, 1).doit())} \\\\
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())

        
        answer_s = f"""
        $\\displaystyle
        \\begin{{aligned}}
        & {latex(Gamma.subs(z, 1))} = {latex(Gamma_func_expr.subs(z, 1).doit())} \\\\
        \\end{{aligned}}
        $
        """
        
        soln_s = "\n\n".join(soln_stmts)
        
                
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        
        return result
        pass
    
    def _problem_define_gaussian_integral(self, **kwargs):
        x = Symbol('x', complex = True)
        
        prob_s = f"""
        Define Gaussian integral
        """
        
        soln_stmts = []
        
        soln_stmt = f"""
        The Gaussian integral is a fundamental integral in mathematics, particularly in probability theory and physics,
        which evaluates the integral of the exponential function with a negative quadratic exponent over the entire 
        real line. It is named after Carl Friedrich Gauss.

        """
        soln_stmts.append(soln_stmt.replace('\n', ' ').strip())
        
        
        Gaussian_expr = sp.exp(-(x**2))
        Gaussian_integral_expr = sp.Integral(Gaussian_expr, (x, -sp.oo, sp.oo))
        Gaussian_integral_expr_sol = Gaussian_integral_expr.doit()
        
        
        soln_stmt = f"""
        $\\displaystyle
        \\begin{{aligned}}
        & {latex(Gaussian_integral_expr)} = {latex(Gaussian_integral_expr_sol)} \\\\
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())

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

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

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

        answer_s = f"""
        $\\displaystyle
        \\begin{{aligned}}
        & {latex(Gaussian_integral_expr)} = {latex(Gaussian_integral_expr_sol)} \\\\
        \\end{{aligned}}
        $
        """
        
        soln_s = "\n\n".join(soln_stmts)
        
                
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        
        return result
        pass
    
    def _problem_proof_gaussian_integral(self, **kwargs):
        x = Symbol('x', complex = True)
        y = Symbol('y', complex = True)
        r = Symbol('r')
        theta = Symbol('theta')
        I = Symbol('I')
        Gaussian_expr = sp.exp(-(x**2))
        Gaussian_integral_expr = sp.Integral(Gaussian_expr, (x, -sp.oo, sp.oo))
        Gaussian_integral_expr_sol = Gaussian_integral_expr.doit()
        
        prob_s = f"""
        Prove Gaussian integral
        $\\displaystyle
        \\begin{{aligned}}
        & {latex(Gaussian_integral_expr)} = {latex(Gaussian_integral_expr_sol)} \\\\
        \\end{{aligned}}
        $
        """
        
        soln_stmts = []
        
        soln_stmt = f"""

        """
        soln_stmts.append(soln_stmt.replace('\n', ' ').strip())
        
        Gaussian_integral_expr_x = Gaussian_integral_expr
        Gaussian_integral_expr_y = Gaussian_integral_expr.subs(x, y)
        Gaussian_integral_expr_xy = sp.Integral(sp.Integral(Gaussian_expr*Gaussian_expr.subs(x, y),(x, -sp.oo, sp.oo)), (y, -sp.oo, sp.oo))
        Gaussian_integral_expr_rtheta_inner_integral = sp.Integral(r*exp(-(r**2)),(r, 0, sp.oo))
        Gaussian_integral_expr_rtheta = sp.Integral(Gaussian_integral_expr_rtheta_inner_integral, (theta, 0, 2*sp.pi))
        Gaussian_integral_expr_rtheta_sol_1 = sp.Integral(Gaussian_integral_expr_rtheta_inner_integral.doit(), (theta, 0, 2*sp.pi))
        Gaussian_integral_expr_rtheta_sol_2 = Gaussian_integral_expr_rtheta.doit()

        soln_stmt = f"""
        $\\displaystyle
        \\begin{{aligned}}
        {latex(I)} &= {latex(Gaussian_integral_expr)} \\\\
        \\Rightarrow {latex(I**2)} &= \\left({latex(Gaussian_integral_expr_x)}\\right) \\cdot \\left({latex(Gaussian_integral_expr_y)}\\right) \\\\
        &= {latex(Gaussian_integral_expr_xy)} \\\\
        &= {latex(Gaussian_integral_expr_rtheta)} \\qquad \\text{{Transformation through Jacobian}} \\\\
        &= {latex(Gaussian_integral_expr_rtheta_sol_1)} \\\\
        &= {latex(Gaussian_integral_expr_rtheta_sol_2)} \\\\
        \\Rightarrow {latex(I)} &= {latex(sqrt(Gaussian_integral_expr_rtheta_sol_2))} \\\\
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())

        soln_stmt = f"""
        $\\displaystyle
        \\begin{{aligned}}
        \\Rightarrow {latex(Gaussian_integral_expr)} &= {latex(sqrt(Gaussian_integral_expr_rtheta_sol_2))} \\\\
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())

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

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

        answer_s = f"""
        """
        
        soln_s = "\n\n".join(soln_stmts)
        
                
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        
        return result
        pass
    
    def _problem_find_laplace_transform_of_half(self, **kwargs):
        z = Symbol('z', complex = True, constant = True)
        Gamma = Function('Gamma')(z)
        x = Symbol('x', complex = True)
        t = Symbol('t')
        
        prob_s = f"""
        Find $\\displaystyle {latex(Gamma.subs(z, Rational(1, 2)))}$
        
        """
        
        soln_stmts = []
        
        soln_stmt = f"""

        """
        soln_stmts.append(soln_stmt.replace('\n', ' ').strip())
        
        Gaussian_expr = sp.exp(-(x**2))
        Gaussian_integral_expr = sp.Integral(Gaussian_expr, (x, -sp.oo, sp.oo))
        Gaussian_integral_expr_sol = Gaussian_integral_expr.doit()
        Gaussian_integral_expr_positive_side = sp.Integral(Gaussian_expr, (x, 0, sp.oo))
        Gaussian_integral_expr_positive_side_sol = Gaussian_integral_expr_positive_side.doit()
        Gamma_expr = sp.exp(-(t))/(2*sqrt(t))
        Gaussian_integral_expr_subs = sp.Integral(Gamma_expr, (t, 0, sp.oo))
        Gamma_expr_simplified =  t**(-Rational(1/2)) * sp.exp(-(t))
        Gaussian_integral_expr_simplified = Rational(1, 2) * sp.Integral(Gamma_expr_simplified, (t, 0, sp.oo))
        soln_stmt = f"""
        We start with the Gaussian integral:
        $\\displaystyle
        \\begin{{aligned}}
        & {latex(Gaussian_integral_expr)} = {latex(Gaussian_integral_expr_sol)} \\\\
        \\Rightarrow & {latex(Gaussian_integral_expr_positive_side)} = {latex(Gaussian_integral_expr_positive_side_sol)} \\qquad \\text{{Taking just the positive side of the gaussian integral}}\\\\
        \\Rightarrow & {latex(Gaussian_integral_expr_subs)} = {latex(Gaussian_integral_expr_positive_side_sol)} \\qquad \\text{{Substituting }} {latex(Eq(x, sqrt(t)))}\\\\
        \\Rightarrow & {latex(Gaussian_integral_expr_simplified)} = {latex(Gaussian_integral_expr_positive_side_sol)} \\\\
        \\Rightarrow & {latex(2 * Gaussian_integral_expr_simplified)} = {latex(2 * Gaussian_integral_expr_positive_side_sol)} \\\\
        \\Rightarrow & {latex(Gamma.subs(z, Rational(1, 2)))} = {latex(2 * Gaussian_integral_expr_positive_side_sol)} \\qquad \\text{{As}} {latex(2 * Gaussian_integral_expr_simplified)} = {latex(Gamma.subs(z, Rational(1, 2)))}\\\\
        
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())

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

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

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

        answer_s = f"""
        $\\displaystyle
        \\Rightarrow & {latex(Gamma.subs(z, Rational(1, 2)))} = {latex(2 * Gaussian_integral_expr_positive_side_sol)} 
        \\end{{aligned}}
        $   
        """
        
        soln_s = "\n\n".join(soln_stmts)
        
                
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        
        return result
        pass
    
    def _problem_solve_improper_fraction(self, **kwargs):
        z = Symbol('z', complex = True, constant = True)
        Gamma = Function('Gamma')(z)
        x = Symbol('x')
        problem_expr = x**(Rational(3, 2))*sp.exp(-(x))
        problem_integral = sp.Integral(problem_expr, (x, 0, sp.oo))
        
        prob_s = f"""
        Evaluate the integral $\\displaystyle {latex(problem_integral)}$
        
        """
        
        soln_stmts = []
        
        soln_stmt = f"""

        """
        soln_stmts.append(soln_stmt.replace('\n', ' ').strip())
        Gamma_expr = x**(z - 1)*sp.exp(-(x))
        Gamma_Function_expr = sp.Integral(Gamma_expr, (x, 0, sp.oo))
        
        numerator_of_z = 5
        for idx in range(numerator_of_z - 2, 0, -2):
            if idx == numerator_of_z - 2:
                latex_str = ''
            list_of_products = list(range(numerator_of_z - 2, idx - 2, -2))
            list_of_products = [Rational(product, 2) for product in list_of_products]
            latex_str = latex_str + f" &= {latex(sp.Mul(*list_of_products))} {latex(Gamma.subs(z, list_of_products[-1]))} \\\\" + '\n'

        Gamma_half = Gamma.subs(z, Rational(1, 2))
        Gamma_half_expr = sqrt(sp.pi)
        
        soln_stmt = f"""
        $\\displaystyle
        \\begin{{aligned}}
        {latex(Gamma)} &= {latex(Gamma_Function_expr)} \\\\
        \\Rightarrow {latex(Gamma.subs(z, Rational(5, 2)))} &= {latex(Gamma_Function_expr.subs(z, Rational(5, 2)))} \\qquad \\text{{For }} {latex(Eq(z, Rational(5, 2)))}\\\\
        {latex_str} \\\\
        &= {latex(sp.Mul(*list_of_products))} {latex(Gamma_half_expr)} \\qquad \\text{{As }} {latex(Eq(Gamma_half, Gamma_half_expr))}\\\\
        {latex(problem_integral)} &= {latex(sp.Mul(*list_of_products))} {latex(Gamma_half_expr)} \\\\
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())
        

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

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

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

        answer_s = f"""
        $\\displaystyle
        \\begin{{aligned}}
        {latex(problem_integral)} &= {latex(sp.Mul(*list_of_products))} {latex(Gamma_half_expr)} \\\\
        \\end{{aligned}}
        $
        """
        
        soln_s = "\n\n".join(soln_stmts)
        
                
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        
        return result
        pass
    
    def _problem_find_relation_laplace_transform_between_factorial(self, **kwargs):
        z = Symbol('z', complex = True, constant = True)
        n = Symbol('n', integer = True, constant = True, positive = True)
        Gamma = Function('Gamma')(z)
        Factorial = sp.factorial(n)
        
        prob_s = f"""
        Find the relation between Gamma function ${latex(Gamma)}$ and factorial ${latex(Factorial)}$
        """
        
        soln_stmts = []
        
        soln_stmt = f"""

        """
        soln_stmts.append(soln_stmt.replace('\n', ' ').strip())
        
        
        soln_stmt = f"""
        Let's assume $\\displaystyle {latex(Eq(Gamma.subs(z, n), Factorial.subs(n, n - 1)))}$ for any positive integer ${latex(n)}$. 
        We need to prove $\\displaystyle {latex(Eq(Gamma.subs(z, n + 1), Factorial))}$
        """
        soln_stmts.append(soln_stmt.strip())
        
        Gamma_Function_expr = (z - 1)*Gamma.subs(z, z - 1)
        Gamma_n = Gamma.subs(z, n)
        Gamma_n_1 = Gamma.subs(z, n + 1)
        Gamma_n_1_expr = Gamma_Function_expr.subs(z, n + 1)
        soln_stmt = f"""
        As we know,
        $\\displaystyle 
        \\begin{{aligned}}  
        & \\Rightarrow {latex(Gamma_n_1)} = {latex(Gamma_n_1_expr)} \\\\
        & \\Rightarrow {latex(Gamma_n_1)} = {latex(Gamma_n_1_expr.subs(Gamma_n, Factorial.subs(n, n - 1)))} \\qquad \\text{{As we assumed }} {latex(Eq(Gamma.subs(z, n), Factorial.subs(n, n - 1)))}\\\\
        & \\Rightarrow {latex(Gamma_n_1)} = {latex(Factorial)} \\\\
        \\end{{aligned}}
        $
        """
        soln_stmts.append(soln_stmt.strip())

        
        soln_stmt = f"""
        Factorial ${latex(Factorial)}$ is a special case of Gamma Function ${latex(Gamma)}$
        """
        soln_stmts.append(soln_stmt.strip())

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

        answer_s = f"""
        """
        
        soln_s = "\n\n".join(soln_stmts)
        
                
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        
        return result
        pass
    
    
    pass
#class LaplaceTransformHelper:
