mathgenerator.algebra

  1from ._latexBuilder import bmatrix
  2import random
  3import math
  4import fractions
  5import sympy
  6
  7
  8def basic_algebra(max_variable=10):
  9    r"""Basic Algebra
 10
 11    | Ex. Problem | Ex. Solution |
 12    | --- | --- |
 13    | $1x + 5 = 5$ | $0$ |
 14    """
 15    a = random.randint(1, max_variable)
 16    b = random.randint(1, max_variable)
 17    c = random.randint(b, max_variable)
 18
 19    # calculate gcd
 20    def calculate_gcd(x, y):
 21        while (y):
 22            x, y = y, x % y
 23        return x
 24
 25    i = calculate_gcd((c - b), a)
 26    x = f"{(c - b)//i}/{a//i}"
 27
 28    if (c - b == 0):
 29        x = "0"
 30    elif a//i == 1:
 31        x = f"{(c - b)//i}"
 32
 33    problem = f"${a}x + {b} = {c}$"
 34    solution = f"${x}$"
 35    return problem, solution
 36
 37
 38def combine_like_terms(max_coef=10, max_exp=20, max_terms=10):
 39    r"""Combine Like Terms
 40
 41    | Ex. Problem | Ex. Solution |
 42    | --- | --- |
 43    | $6x^{9} + 3x^{2} + 5x^{19} + 3x^{17}$ | $3x^{2} + 6x^{9} + 3x^{17} + 5x^{19}$ |
 44    """
 45    numTerms = random.randint(1, max_terms)
 46
 47    coefs = [random.randint(1, max_coef) for _ in range(numTerms)]
 48    exponents = [
 49        random.randint(1, max(max_exp - 1, 2)) for _ in range(numTerms)
 50    ]
 51
 52    problem = " + ".join(
 53        [f"{coefs[i]}x^{{{exponents[i]}}}" for i in range(numTerms)])
 54    d = {}
 55    for i in range(numTerms):
 56        if exponents[i] in d:
 57            d[exponents[i]] += coefs[i]
 58        else:
 59            d[exponents[i]] = coefs[i]
 60    solution = " + ".join([f"{d[k]}x^{{{k}}}" for k in sorted(d)])
 61
 62    return f'${problem}$', f'${solution}$'
 63
 64
 65def complex_quadratic(prob_type=0, max_range=10):
 66    r"""Complex Quadratic Equation
 67
 68    | Ex. Problem | Ex. Solution |
 69    | --- | --- |
 70    | Find the roots of given Quadratic Equation $x^2 + 8x + 8 = 0$ | $((-1.172, -6.828)) = (\frac{-8 + \sqrt{32}}{2}, (\frac{-8 - \sqrt{32}}{2})$ |
 71    """
 72    if prob_type < 0 or prob_type > 1:
 73        print("prob_type not supported")
 74        print("prob_type = 0 for real roots problems ")
 75        print("prob_tpye = 1 for imaginary roots problems")
 76        return None
 77    if prob_type == 0:
 78        d = -1
 79        while d < 0:
 80            a = random.randrange(1, max_range)
 81            b = random.randrange(1, max_range)
 82            c = random.randrange(1, max_range)
 83
 84            d = (b**2 - 4 * a * c)
 85    else:
 86        d = 0
 87        while d >= 0:
 88            a = random.randrange(1, max_range)
 89            b = random.randrange(1, max_range)
 90            c = random.randrange(1, max_range)
 91
 92            d = (b**2 - 4 * a * c)
 93
 94    eq = ''
 95
 96    if a == 1:
 97        eq += 'x^2 + '
 98    else:
 99        eq += str(a) + 'x^2 + '
100
101    if b == 1:
102        eq += 'x + '
103    else:
104        eq += str(b) + 'x + '
105
106    eq += str(c) + ' = 0'
107
108    problem = f'Find the roots of given Quadratic Equation ${eq}$'
109
110    if d < 0:
111        sqrt_d = (-d)**0.5
112
113        if sqrt_d - int(sqrt_d) == 0:
114            sqrt_d = int(sqrt_d)
115            solution = rf'(\frac{{{-b} + {sqrt_d}i}}{{{2*a}}}, \frac{{{-b} - {sqrt_d}i}}{{{2*a}}})'
116        else:
117            solution = rf'(\frac{{{-b} + \sqrt{{{-d}}}i}}{{{2*a}}}, \frac{{{-b} - \sqrt{{{-d}}}i}}{{{2*a}}})'
118
119        return problem, solution
120
121    else:
122        s_root1 = round((-b + (d)**0.5) / (2 * a), 3)
123        s_root2 = round((-b - (d)**0.5) / (2 * a), 3)
124
125        sqrt_d = (d)**0.5
126
127        if sqrt_d - int(sqrt_d) == 0:
128            sqrt_d = int(sqrt_d)
129            g_sol = rf'(\frac{{{-b} + {sqrt_d}}}{{{2*a}}}, \frac{{{-b} - {sqrt_d}}}{{{2*a}}})'
130        else:
131            g_sol = rf'(\frac{{{-b} + \sqrt{{{d}}}}}{{{2*a}}}, (\frac{{{-b} - \sqrt{{{d}}}}}{{{2*a}}})'
132
133        solution = f'$({s_root1, s_root2}) = {g_sol}$'
134
135        return problem, solution
136
137
138def compound_interest(max_principle=10000, max_rate=10, max_time=10):
139    r"""Compound Interest
140
141    | Ex. Problem | Ex. Solution |
142    | --- | --- |
143    | Compound interest for a principle amount of $2679$ dollars, $9$% rate of interest and for a time period of $3$ years is $=$ | $3469.38$ |
144    """
145    p = random.randint(1000, max_principle)
146    r = random.randint(1, max_rate)
147    n = random.randint(1, max_time)
148    a = round(p * (1 + r / 100)**n, 2)
149
150    problem = f"Compound interest for a principle amount of ${p}$ dollars, ${r}$% rate of interest and for a time period of ${n}$ years is $=$"
151    return problem, f'${a}$'
152
153
154def distance_two_points(max_val_xy=20, min_val_xy=-20):
155    r"""Distance between 2 points
156
157    | Ex. Problem | Ex. Solution |
158    | --- | --- |
159    | Find the distance between $(-19, -6)$ and $(15, -16)$ | $\sqrt{1256}$ |
160    """
161    if max_val_xy < min_val_xy:
162        max_val_xy, min_val_xy = min_val_xy, max_val_xy
163
164    point1X = random.randint(min_val_xy, max_val_xy + 1)
165    point1Y = random.randint(min_val_xy, max_val_xy + 1)
166    point2X = random.randint(min_val_xy, max_val_xy + 1)
167    point2Y = random.randint(min_val_xy, max_val_xy + 1)
168
169    distanceSq = (point1X - point2X)**2 + (point1Y - point2Y)**2
170
171    solution = rf"$\sqrt{{{distanceSq}}}$"
172    problem = f"Find the distance between $({point1X}, {point1Y})$ and $({point2X}, {point2Y})$"
173    return problem, solution
174
175
176def expanding(range_x1=10, range_x2=10, range_a=10, range_b=10):
177    r"""Expanding Factored Binomial
178
179    | Ex. Problem | Ex. Solution |
180    | --- | --- |
181    |$(x-6)(-3x-3)$ | $x^2+18x+18$ |
182    """
183    x1 = random.randint(-range_x1, range_x1)
184    x2 = random.randint(-range_x2, range_x2)
185    a = random.randint(-range_a, range_a)
186    b = random.randint(-range_b, range_b)
187
188    def intParser(z):
189        if (z > 0):
190            return f"+{z}"
191        elif (z < 0):
192            return f"-{abs(z)}"
193        else:
194            return ""
195
196    c1 = intParser(a * b)
197    c2 = intParser((a * x2) + (b * x1))
198    c3 = intParser(x1 * x2)
199
200    p1 = intParser(a)
201    p2 = intParser(x1)
202    p3 = intParser(b)
203    p4 = intParser(x2)
204
205    if p1 == "+1":
206        p1 = ""
207    elif len(p1) > 0 and p1[0] == "+":
208        p1 = p1[1:]
209    if p3 == "+1":
210        p3 = ""
211    elif p3[0] == "+":
212        p3 = p3[1:]
213
214    if c1 == "+1":
215        c1 = ""
216    elif len(c1) > 0 and c1[0] == "+":
217        c1 = c1[1:]  # Cuts off the plus for readability
218    if c2 == "+1":
219        c2 = ""
220
221    problem = f"$({p1}x{p2})({p3}x{p4})$"
222    solution = f"${c1}x^2{c2}x{c3}$"
223    return problem, solution
224
225
226def factoring(range_x1=10, range_x2=10):
227    r"""Factoring Quadratic
228    Given a quadratic equation in the form x^2 + bx + c, factor it into it's roots (x - x1)(x -x2)
229
230    | Ex. Problem | Ex. Solution |
231    | --- | --- |
232    | $x^2+2x-24$ | $(x-4)(x+6)$ |
233    """
234    x1 = random.randint(-range_x1, range_x1)
235    x2 = random.randint(-range_x2, range_x2)
236
237    def intParser(z):
238        if (z > 0):
239            return f"+{z}"
240        elif (z < 0):
241            return f"-{abs(z)}"
242        else:
243            return ""
244
245    b = intParser(x1 + x2)
246    c = intParser(x1 * x2)
247
248    if b == "+1":
249        b = "+"
250    if b == "":
251        problem = f"x^2{c}"
252    else:
253        problem = f"x^2{b}x{c}"
254
255    x1 = intParser(x1)
256    x2 = intParser(x2)
257    solution = f"$(x{x1})(x{x2})$"
258    return f"${problem}$", solution
259
260
261def int_matrix_22_determinant(max_matrix_val=100):
262    r"""Determinant to 2x2 Matrix
263
264    | Ex. Problem | Ex. Solution |
265    | --- | --- |
266    | $\det \begin{bmatrix} 88 & 40 \\\ 9 & 91 \end{bmatrix}= $ | $7648$ |
267    """
268    a = random.randint(0, max_matrix_val)
269    b = random.randint(0, max_matrix_val)
270    c = random.randint(0, max_matrix_val)
271    d = random.randint(0, max_matrix_val)
272
273    determinant = a * d - b * c
274    lst = [[a, b], [c, d]]
275
276    problem = rf"$\det {bmatrix(lst)}= $"
277    solution = f"${determinant}$"
278    return problem, solution
279
280
281def intersection_of_two_lines(min_m=-10,
282                              max_m=10,
283                              min_b=-10,
284                              max_b=10,
285                              min_denominator=1,
286                              max_denominator=6):
287    r"""Intersection of two lines
288
289    | Ex. Problem | Ex. Solution |
290    | --- | --- |
291    | Find the point of intersection of the two lines: $y = \frac{-2}{6}x + 3$ and $y = \frac{3}{6}x - 8$ | $(\frac{66}{5}, \frac{-7}{5})$ |
292    """
293    def generateEquationString(m, b):
294        """
295        Generates an equation given the slope and intercept.
296        It handles cases where m is fractional.
297        It also ensures that we don't have weird signs such as y = mx + -b.
298        """
299        if m[0] == 0:
300            m = 0
301        elif abs(m[0]) == abs(m[1]):
302            m = m[0] // m[1]
303        elif m[1] == 1:
304            m = m[0]
305        else:
306            m = rf"\frac{{{m[0]}}}{{{m[1]}}}"
307        base = "y ="
308        if m != 0:
309            if m == 1:
310                base = f"{base} x"
311            elif m == -1:
312                base = f"{base} -x"
313            else:
314                base = f"{base} {m}x"
315        if b > 0:
316            if m == 0:
317                return f"{base} {b}"
318            else:
319                return f"{base} + {b}"
320        elif b < 0:
321            if m == 0:
322                return f"{base} -{b * -1}"
323            else:
324                return f"{base} - {b * -1}"
325        else:
326            if m == 0:
327                return f"{base} 0"
328            else:
329                return base
330
331    def fractionToString(x):
332        """
333        Converts the given fractions.Fraction into a string.
334        """
335        if x.denominator == 1:
336            x = x.numerator
337        else:
338            x = rf"\frac{{{x.numerator}}}{{{x.denominator}}}"
339        return x
340
341    m1 = (random.randint(min_m, max_m),
342          random.randint(min_denominator, max_denominator))
343    m2 = (random.randint(min_m, max_m),
344          random.randint(min_denominator, max_denominator))
345
346    b1 = random.randint(min_b, max_b)
347    b2 = random.randint(min_b, max_b)
348
349    eq1 = generateEquationString(m1, b1)
350    eq2 = generateEquationString(m2, b2)
351
352    problem = f"Find the point of intersection of the two lines: ${eq1}$ and ${eq2}$"
353
354    m1 = fractions.Fraction(*m1)
355    m2 = fractions.Fraction(*m2)
356    # if m1 == m2 then the slopes are equal
357    # This can happen if both line are the same
358    # Or if they are parallel
359    # In either case there is no intersection
360
361    if m1 == m2:
362        solution = "No Solution"
363    else:
364        intersection_x = (b1 - b2) / (m2 - m1)
365        intersection_y = ((m2 * b1) - (m1 * b2)) / (m2 - m1)
366        solution = f"$({fractionToString(intersection_x)}, {fractionToString(intersection_y)})$"
367
368    return problem, solution
369
370
371def invert_matrix(square_matrix_dimension=3,
372                  max_matrix_element=99,
373                  only_integer_elements_in_inverted_matrixe=True):
374    r"""Invert Matrix
375
376    | Ex. Problem | Ex. Solution |
377    | --- | --- |
378    | Inverse of Matrix $\begin{bmatrix} 4 & 1 & 4 \\\ 5 & 1 & 5 \\\ 12 & 3 & 13 \end{bmatrix}$ is: | $\begin{bmatrix} 2 & 1 & -1 \\\ 5 & -4 & 0 \\\ -3 & 0 & 1 \end{bmatrix}$ |
379    """
380    if only_integer_elements_in_inverted_matrixe is True:
381        isItOk = False
382        Mat = list()
383        while (isItOk is False):
384            Mat = list()
385            for i in range(0, square_matrix_dimension):
386                z = list()
387                for j in range(0, square_matrix_dimension):
388                    z.append(0)
389                z[i] = 1
390                Mat.append(z)
391            MaxAllowedMatrixElement = math.ceil(
392                pow(max_matrix_element, 1 / (square_matrix_dimension)))
393            randomlist = random.sample(range(0, MaxAllowedMatrixElement + 1),
394                                       square_matrix_dimension)
395
396            for i in range(0, square_matrix_dimension):
397                if i == square_matrix_dimension - 1:
398                    Mat[0] = [
399                        j + (k * randomlist[i])
400                        for j, k in zip(Mat[0], Mat[i])
401                    ]
402                else:
403                    Mat[i + 1] = [
404                        j + (k * randomlist[i])
405                        for j, k in zip(Mat[i + 1], Mat[i])
406                    ]
407
408            for i in range(1, square_matrix_dimension - 1):
409                Mat[i] = [
410                    sum(i)
411                    for i in zip(Mat[square_matrix_dimension - 1], Mat[i])
412                ]
413
414            isItOk = True
415            for i in Mat:
416                for j in i:
417                    if j > max_matrix_element:
418                        isItOk = False
419                        break
420                if isItOk is False:
421                    break
422
423        random.shuffle(Mat)
424        Mat = sympy.Matrix(Mat)
425        Mat = sympy.Matrix.transpose(Mat)
426        Mat = Mat.tolist()
427        random.shuffle(Mat)
428        Mat = sympy.Matrix(Mat)
429        Mat = sympy.Matrix.transpose(Mat)
430
431    else:
432        randomlist = list(sympy.primerange(0, max_matrix_element + 1))
433        plist = random.sample(randomlist, square_matrix_dimension)
434        randomlist = random.sample(
435            range(0, max_matrix_element + 1),
436            square_matrix_dimension * square_matrix_dimension)
437        randomlist = list(set(randomlist) - set(plist))
438        n_list = random.sample(
439            randomlist,
440            square_matrix_dimension * (square_matrix_dimension - 1))
441        Mat = list()
442        for i in range(0, square_matrix_dimension):
443            z = list()
444            z.append(plist[i])
445            for j in range(0, square_matrix_dimension - 1):
446                z.append(n_list[(i * square_matrix_dimension) + j - i])
447            random.shuffle(z)
448            Mat.append(z)
449        Mat = sympy.Matrix(Mat)
450
451    problem = 'Inverse of Matrix $' + bmatrix(Mat.tolist()) + '$ is:'
452    solution = f'${bmatrix(sympy.Matrix.inv(Mat).tolist())}$'
453    return problem, solution
454
455
456def linear_equations(n=2, var_range=20, coeff_range=20):
457    r"""Linear Equations
458
459    | Ex. Problem | Ex. Solution |
460    | --- | --- |
461    | Given the equations $10x + -20y = 310$ and $-16x + -17y = 141$, solve for $x$ and $y$ | $x = 5$, $y = -13$ |
462    """
463    if n > 10:
464        print("[!] n cannot be greater than 10")
465        return None, None
466
467    vars = ['x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g'][:n]
468    soln = [random.randint(-var_range, var_range) for i in range(n)]
469    problem = list()
470    solution = "$, $".join(
471        ["{} = {}".format(vars[i], soln[i]) for i in range(n)])
472
473    for _ in range(n):
474        coeff = [random.randint(-coeff_range, coeff_range) for i in range(n)]
475        res = sum([coeff[i] * soln[i] for i in range(n)])
476        prob = [
477            "{}{}".format(coeff[i], vars[i]) if coeff[i] != 0 else ""
478            for i in range(n)
479        ]
480
481        while "" in prob:
482            prob.remove("")
483        prob = " + ".join(prob) + " = " + str(res)
484        problem.append(prob)
485
486    # problem = "\n".join(problem)
487    problem = "$ and $".join(problem)
488
489    return f'Given the equations ${problem}$, solve for $x$ and $y$', f'${solution}$'
490
491
492def line_equation_from_2_points(max_val=20):
493    r"""Equation of Line from Two Points
494
495    | Ex. Problem | Ex. Solution |
496    | --- | --- |
497    | Find the equation of the line passing through the points $(-19,-8)$ and $(-2,0)$. | $y=\frac{8}{17}x+\frac{16}{17}$ |
498    """
499    x1 = random.randint(-max_val, max_val)
500    x2 = random.randint(-max_val, max_val)
501    if x1 == x2:
502        return line_equation_from_2_points(max_val=max_val)
503    y1 = random.randint(-max_val, max_val)
504    y2 = random.randint(-max_val, max_val)
505    m1 = (y2 - y1) // math.gcd(y2 - y1, x2 - x1)
506    m2 = (x2 - x1) // math.gcd(y2 - y1, x2 - x1)
507    c1 = (y1 * (x2 - x1) - (y2 - y1) * x1) // math.gcd(y1 * (x2 - x1) - (y2 - y1) * x1, (x2 - x1))
508    c2 = (x2 - x1) // math.gcd(y1 * (x2 - x1) - (y2 - y1) * x1, (x2 - x1))
509    c = rf"{'+' if c1 >= 0 else '-'}\frac{{{abs(c1)}}}{{{c2}}}" if c1 != 0 else ""
510    if c2 < 0:
511        c2 = -c2
512        c1 = -c1
513        c = rf"{'+' if c1 >= 0 else '-'}\frac{{{abs(c1)}}}{{{c2}}}"
514    if c2 == 1:
515        c = f"{c1:+}"
516
517    problem = f'Find the equation of the line passing through the points $({x1},{y1})$ and $({x2},{y2})$.'
518
519    if m1 == 0:
520        return problem, f"$y={c}$"
521    if m2 < 0:
522        m1 = -m1
523        m2 = -m2
524    if m2 == 1:
525        if m1 == 1:
526            return problem, f"$y=x{c}$"
527        if m1 == -1:
528            return problem, f"$y=-x{c}$"
529        return problem, f"y={m1}x{c}"
530
531    return problem, rf"$y=\frac{{{m1}}}{{{m2}}}x{c}$"
532
533
534def log(max_base=3, max_val=8):
535    r"""Logarithm
536
537    | Ex. Problem | Ex. Solution |
538    | --- | --- |
539    | $log_{3}(243)=$ | $5$ |
540    """
541    a = random.randint(1, max_val)
542    b = random.randint(2, max_base)
543    c = pow(b, a)
544
545    problem = f'$log_{{{b}}}({c})=$'
546    solution = f'${a}$'
547    return problem, solution
548
549
550def matrix_multiplication(max_val=100, max_dim=10):
551    r"""Multiply Two Matrices
552
553    | Ex. Problem | Ex. Solution |
554    | --- | --- |
555    | Multiply $\begin{bmatrix} 15 & 72 \\\ 64 & -20 \\\ 18 & 59 \\\ -21 & -55 \\\ 20 & -12 \\\ -75 & -42 \\\ 47 & 89 \\\ -53 & 27 \\\ -56 & 44 \end{bmatrix}$ and $\begin{bmatrix} 49 & -2 & 68 & -28 \\\ 49 & 6 & 83 & 42 \end{bmatrix}$ | $\begin{bmatrix} 4263 & 402 & 6996 & 2604 \\\ 2156 & -248 & 2692 & -2632 \\\ 3773 & 318 & 6121 & 1974 \\\ -3724 & -288 & -5993 & -1722 \\\ 392 & -112 & 364 & -1064 \\\ -5733 & -102 & -8586 & 336 \\\ 6664 & 440 & 10583 & 2422 \\\ -1274 & 268 & -1363 & 2618 \\\ -588 & 376 & -156 & 3416 \end{bmatrix}$ |
556    """
557    m = random.randint(2, max_dim)
558    n = random.randint(2, max_dim)
559    k = random.randint(2, max_dim)
560
561    # generate matrices a and b
562    a = [[random.randint(-max_val, max_val) for _ in range(n)]
563         for _ in range(m)]
564    b = [[random.randint(-max_val, max_val) for _ in range(k)]
565         for _ in range(n)]
566
567    res = []
568    for r in range(m):
569        res.append([])
570        for c in range(k):
571            temp = 0
572            for t in range(n):
573                temp += a[r][t] * b[t][c]
574            res[r].append(temp)
575
576    problem = f"Multiply ${bmatrix(a)}$ and ${bmatrix(b)}$"
577    solution = f'${bmatrix(res)}$'
578    return problem, solution
579
580
581def midpoint_of_two_points(max_value=20):
582    r"""Midpoint of two points
583
584    | Ex. Problem | Ex. Solution |
585    | --- | --- |
586    | The midpoint of $(-8,10)$ and $(18,0) = $ | $(5.0,5.0)$ |
587    """
588    x1 = random.randint(-20, max_value)
589    y1 = random.randint(-20, max_value)
590    x2 = random.randint(-20, max_value)
591    y2 = random.randint(-20, max_value)
592    xm = (x1 + x2) / 2
593    ym = (y1 + y2) / 2
594
595    problem = f"The midpoint of $({x1},{y1})$ and $({x2},{y2}) = $"
596    solution = f"$({xm},{ym})$"
597    return problem, solution
598
599
600def multiply_complex_numbers(min_real_imaginary_num=-20,
601                             max_real_imaginary_num=20):
602    r"""Multiplication of 2 complex numbers
603
604    | Ex. Problem | Ex. Solution |
605    | --- | --- |
606    | $(14+18j) * (14+15j) = $ | $(-74+462j)$ |
607    """
608    num1 = complex(
609        random.randint(min_real_imaginary_num, max_real_imaginary_num),
610        random.randint(min_real_imaginary_num, max_real_imaginary_num))
611    num2 = complex(
612        random.randint(min_real_imaginary_num, max_real_imaginary_num),
613        random.randint(min_real_imaginary_num, max_real_imaginary_num))
614    product = num1 * num2
615
616    problem = f"${num1} * {num2} = $"
617    solution = f'${product}$'
618    return problem, solution
619
620
621def multiply_int_to_22_matrix(max_matrix_val=10, max_res=100):
622    r"""Multiply Integer to 2x2 Matrix
623
624    | Ex. Problem | Ex. Solution |
625    | --- | --- |
626    | $5 * \begin{bmatrix} 1 & 0 \\\ 2 & 9 \end{bmatrix} =$ | $\begin{bmatrix} 5 & 0 \\\ 10 & 45 \end{bmatrix}$ |
627    """
628    a = random.randint(0, max_matrix_val)
629    b = random.randint(0, max_matrix_val)
630    c = random.randint(0, max_matrix_val)
631    d = random.randint(0, max_matrix_val)
632
633    constant = random.randint(0, int(max_res / max(a, b, c, d)))
634
635    a1 = a * constant
636    b1 = b * constant
637    c1 = c * constant
638    d1 = d * constant
639    lst = [[a, b], [c, d]]
640    lst1 = [[a1, b1], [c1, d1]]
641
642    problem = f'${constant} * {bmatrix(lst)} =$'
643    solution = f'${bmatrix(lst1)}$'
644    return problem, solution
645
646
647def quadratic_equation(max_val=100):
648    r"""Quadratic Equation
649
650    | Ex. Problem | Ex. Solution |
651    | --- | --- |
652    | What are the zeros of the quadratic equation $22x^2+137x+25=0$ | ${-0.19, -6.04}$ |
653    """
654    a = random.randint(1, max_val)
655    c = random.randint(1, max_val)
656    b = random.randint(
657        round(math.sqrt(4 * a * c)) + 1,
658        round(math.sqrt(4 * max_val * max_val)))
659    D = math.sqrt(b * b - 4 * a * c)
660    res = {round((-b + D) / (2 * a), 2), round((-b - D) / (2 * a), 2)}
661
662    problem = f"What are the zeros of the quadratic equation ${a}x^2+{b}x+{c}=0$"
663    solution = f'${res}$'
664    return problem, solution
665
666
667def simple_interest(max_principle=10000, max_rate=10, max_time=10):
668    r"""Simple Interest
669
670    | Ex. Problem | Ex. Solution |
671    | --- | --- |
672    | Simple interest for a principle amount of $7217$ dollars, $3$% rate of interest and for a time period of $10$ years is $=$ | $2165.1$ |
673    """
674    p = random.randint(1000, max_principle)
675    r = random.randint(1, max_rate)
676    t = random.randint(1, max_time)
677    s = round((p * r * t) / 100, 2)
678
679    problem = f"Simple interest for a principle amount of ${p}$ dollars, ${r}$% rate of interest and for a time period of ${t}$ years is $=$ "
680    solution = f'${s}$'
681    return problem, solution
682
683
684def system_of_equations(range_x=10, range_y=10, coeff_mult_range=10):
685    r"""Solve a System of Equations in R^2
686
687    | Ex. Problem | Ex. Solution |
688    | --- | --- |
689    | Given $-x + 5y = -28$ and $9x + 2y = 64$, solve for $x$ and $y$. | $x = 8$, $y = -4$ |
690    """
691    # Generate solution point first
692    x = random.randint(-range_x, range_x)
693    y = random.randint(-range_y, range_y)
694    # Start from reduced echelon form (coeffs 1)
695    c1 = [1, 0, x]
696    c2 = [0, 1, y]
697
698    def randNonZero():
699        return random.choice(
700            [i for i in range(-coeff_mult_range, coeff_mult_range) if i != 0])
701
702    # Add random (non-zero) multiple of equations (rows) to each other
703    c1_mult = randNonZero()
704    c2_mult = randNonZero()
705    new_c1 = [c1[i] + c1_mult * c2[i] for i in range(len(c1))]
706    new_c2 = [c2[i] + c2_mult * c1[i] for i in range(len(c2))]
707    # For extra randomness, now add random (non-zero) multiples of original rows
708    # to themselves
709    c1_mult = randNonZero()
710    c2_mult = randNonZero()
711    new_c1 = [new_c1[i] + c1_mult * c1[i] for i in range(len(c1))]
712    new_c2 = [new_c2[i] + c2_mult * c2[i] for i in range(len(c2))]
713
714    def coeffToFuncString(coeffs):
715        # lots of edge cases for perfect formatting!
716        x_sign = '-' if coeffs[0] < 0 else ''
717        # No redundant 1s
718        x_coeff = str(abs(coeffs[0])) if abs(coeffs[0]) != 1 else ''
719        # If x coeff is 0, dont include x
720        x_str = f'{x_sign}{x_coeff}x' if coeffs[0] != 0 else ''
721        # if x isn't included and y is positive, dont include operator
722        op = ' - ' if coeffs[1] < 0 else (' + ' if x_str != '' else '')
723        # No redundant 1s
724        y_coeff = abs(coeffs[1]) if abs(coeffs[1]) != 1 else ''
725        # Don't include if 0, unless x is also 0 (probably never happens)
726        y_str = f'{y_coeff}y' if coeffs[1] != 0 else (
727            '' if x_str != '' else '0')
728        return f'{x_str}{op}{y_str} = {coeffs[2]}'
729
730    problem = f"Given ${coeffToFuncString(new_c1)}$ and ${coeffToFuncString(new_c2)}$, solve for $x$ and $y$."
731    solution = f"$x = {x}$, $y = {y}$"
732    return problem, solution
733    # Add random (non-zero) multiple of equations to each other
734
735
736def vector_cross(min_val=-20, max_val=20):
737    r"""Cross product of 2 vectors
738
739    | Ex. Problem | Ex. Solution |
740    | --- | --- |
741    | $[-1, -4, 10] \times [-11, 1, -16] = $ | $[54, -126, -45]$ |
742    """
743    a = [random.randint(min_val, max_val) for _ in range(3)]
744    b = [random.randint(min_val, max_val) for _ in range(3)]
745    c = [
746        a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],
747        a[0] * b[1] - a[1] * b[0]
748    ]
749
750    problem = rf"${a} \times {b} = $"
751    solution = f"${c}$"
752    return problem, solution
753
754
755def vector_dot(min_val=-20, max_val=20):
756    r"""Dot product of 2 vectors
757
758    | Ex. Problem | Ex. Solution |
759    | --- | --- |
760    | $[12, -9, -8]\cdot[-9, 8, 1]=$ | $-188$ |
761    """
762    a = [random.randint(min_val, max_val) for i in range(3)]
763    b = [random.randint(min_val, max_val) for i in range(3)]
764    c = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
765
766    problem = rf'${a}\cdot{b}=$'
767    solution = f'${c}$'
768    return problem, solution
769
770
771def orthogonal_projection(min_val=-10, max_val=10):
772    r"""Orthogonal Projection
773
774    | Ex. Problem | Ex. Solution |
775    | --- | --- |
776    | Find the orthogonal projection of $[2, 3]$ onto $[4, -7]$ | $[\frac{-4}{5}, \frac{7}{5}]$ |
777    """
778    v = [random.randint(min_val, max_val) for _ in range(2)]
779    u = [random.randint(min_val, max_val) for _ in range(2)]
780    dot_t = v[0] * u[0] + v[1] * u[1]
781    dot_b = u[0] * u[0] + u[1] * u[1]
782    frac = fractions.Fraction(dot_t, dot_b).limit_denominator()
783    y = [frac * u[0], frac * u[1]]
784
785    if y[0].denominator != 1:
786        y[0] = rf'\frac{{{y[0].numerator}}}{{{y[0].denominator}}}'
787    if y[1].denominator != 1:
788        y[1] = rf'\frac{{{y[1].numerator}}}{{{y[1].denominator}}}'
789
790    problem = f'Find the orthogonal projection of ${v}$ onto ${u}$'
791    solution = f'$[{y[0]}, {y[1]}]$'
792    return problem, solution
def basic_algebra(max_variable=10):
 9def basic_algebra(max_variable=10):
10    r"""Basic Algebra
11
12    | Ex. Problem | Ex. Solution |
13    | --- | --- |
14    | $1x + 5 = 5$ | $0$ |
15    """
16    a = random.randint(1, max_variable)
17    b = random.randint(1, max_variable)
18    c = random.randint(b, max_variable)
19
20    # calculate gcd
21    def calculate_gcd(x, y):
22        while (y):
23            x, y = y, x % y
24        return x
25
26    i = calculate_gcd((c - b), a)
27    x = f"{(c - b)//i}/{a//i}"
28
29    if (c - b == 0):
30        x = "0"
31    elif a//i == 1:
32        x = f"{(c - b)//i}"
33
34    problem = f"${a}x + {b} = {c}$"
35    solution = f"${x}$"
36    return problem, solution

Basic Algebra

Ex. Problem Ex. Solution
$1x + 5 = 5$ $0$
def combine_like_terms(max_coef=10, max_exp=20, max_terms=10):
39def combine_like_terms(max_coef=10, max_exp=20, max_terms=10):
40    r"""Combine Like Terms
41
42    | Ex. Problem | Ex. Solution |
43    | --- | --- |
44    | $6x^{9} + 3x^{2} + 5x^{19} + 3x^{17}$ | $3x^{2} + 6x^{9} + 3x^{17} + 5x^{19}$ |
45    """
46    numTerms = random.randint(1, max_terms)
47
48    coefs = [random.randint(1, max_coef) for _ in range(numTerms)]
49    exponents = [
50        random.randint(1, max(max_exp - 1, 2)) for _ in range(numTerms)
51    ]
52
53    problem = " + ".join(
54        [f"{coefs[i]}x^{{{exponents[i]}}}" for i in range(numTerms)])
55    d = {}
56    for i in range(numTerms):
57        if exponents[i] in d:
58            d[exponents[i]] += coefs[i]
59        else:
60            d[exponents[i]] = coefs[i]
61    solution = " + ".join([f"{d[k]}x^{{{k}}}" for k in sorted(d)])
62
63    return f'${problem}$', f'${solution}$'

Combine Like Terms

Ex. Problem Ex. Solution
$6x^{9} + 3x^{2} + 5x^{19} + 3x^{17}$ $3x^{2} + 6x^{9} + 3x^{17} + 5x^{19}$
def complex_quadratic(prob_type=0, max_range=10):
 66def complex_quadratic(prob_type=0, max_range=10):
 67    r"""Complex Quadratic Equation
 68
 69    | Ex. Problem | Ex. Solution |
 70    | --- | --- |
 71    | Find the roots of given Quadratic Equation $x^2 + 8x + 8 = 0$ | $((-1.172, -6.828)) = (\frac{-8 + \sqrt{32}}{2}, (\frac{-8 - \sqrt{32}}{2})$ |
 72    """
 73    if prob_type < 0 or prob_type > 1:
 74        print("prob_type not supported")
 75        print("prob_type = 0 for real roots problems ")
 76        print("prob_tpye = 1 for imaginary roots problems")
 77        return None
 78    if prob_type == 0:
 79        d = -1
 80        while d < 0:
 81            a = random.randrange(1, max_range)
 82            b = random.randrange(1, max_range)
 83            c = random.randrange(1, max_range)
 84
 85            d = (b**2 - 4 * a * c)
 86    else:
 87        d = 0
 88        while d >= 0:
 89            a = random.randrange(1, max_range)
 90            b = random.randrange(1, max_range)
 91            c = random.randrange(1, max_range)
 92
 93            d = (b**2 - 4 * a * c)
 94
 95    eq = ''
 96
 97    if a == 1:
 98        eq += 'x^2 + '
 99    else:
100        eq += str(a) + 'x^2 + '
101
102    if b == 1:
103        eq += 'x + '
104    else:
105        eq += str(b) + 'x + '
106
107    eq += str(c) + ' = 0'
108
109    problem = f'Find the roots of given Quadratic Equation ${eq}$'
110
111    if d < 0:
112        sqrt_d = (-d)**0.5
113
114        if sqrt_d - int(sqrt_d) == 0:
115            sqrt_d = int(sqrt_d)
116            solution = rf'(\frac{{{-b} + {sqrt_d}i}}{{{2*a}}}, \frac{{{-b} - {sqrt_d}i}}{{{2*a}}})'
117        else:
118            solution = rf'(\frac{{{-b} + \sqrt{{{-d}}}i}}{{{2*a}}}, \frac{{{-b} - \sqrt{{{-d}}}i}}{{{2*a}}})'
119
120        return problem, solution
121
122    else:
123        s_root1 = round((-b + (d)**0.5) / (2 * a), 3)
124        s_root2 = round((-b - (d)**0.5) / (2 * a), 3)
125
126        sqrt_d = (d)**0.5
127
128        if sqrt_d - int(sqrt_d) == 0:
129            sqrt_d = int(sqrt_d)
130            g_sol = rf'(\frac{{{-b} + {sqrt_d}}}{{{2*a}}}, \frac{{{-b} - {sqrt_d}}}{{{2*a}}})'
131        else:
132            g_sol = rf'(\frac{{{-b} + \sqrt{{{d}}}}}{{{2*a}}}, (\frac{{{-b} - \sqrt{{{d}}}}}{{{2*a}}})'
133
134        solution = f'$({s_root1, s_root2}) = {g_sol}$'
135
136        return problem, solution

Complex Quadratic Equation

Ex. Problem Ex. Solution
Find the roots of given Quadratic Equation $x^2 + 8x + 8 = 0$ $((-1.172, -6.828)) = (\frac{-8 + \sqrt{32}}{2}, (\frac{-8 - \sqrt{32}}{2})$
def compound_interest(max_principle=10000, max_rate=10, max_time=10):
139def compound_interest(max_principle=10000, max_rate=10, max_time=10):
140    r"""Compound Interest
141
142    | Ex. Problem | Ex. Solution |
143    | --- | --- |
144    | Compound interest for a principle amount of $2679$ dollars, $9$% rate of interest and for a time period of $3$ years is $=$ | $3469.38$ |
145    """
146    p = random.randint(1000, max_principle)
147    r = random.randint(1, max_rate)
148    n = random.randint(1, max_time)
149    a = round(p * (1 + r / 100)**n, 2)
150
151    problem = f"Compound interest for a principle amount of ${p}$ dollars, ${r}$% rate of interest and for a time period of ${n}$ years is $=$"
152    return problem, f'${a}$'

Compound Interest

Ex. Problem Ex. Solution
Compound interest for a principle amount of $2679$ dollars, $9$% rate of interest and for a time period of $3$ years is $=$ $3469.38$
def distance_two_points(max_val_xy=20, min_val_xy=-20):
155def distance_two_points(max_val_xy=20, min_val_xy=-20):
156    r"""Distance between 2 points
157
158    | Ex. Problem | Ex. Solution |
159    | --- | --- |
160    | Find the distance between $(-19, -6)$ and $(15, -16)$ | $\sqrt{1256}$ |
161    """
162    if max_val_xy < min_val_xy:
163        max_val_xy, min_val_xy = min_val_xy, max_val_xy
164
165    point1X = random.randint(min_val_xy, max_val_xy + 1)
166    point1Y = random.randint(min_val_xy, max_val_xy + 1)
167    point2X = random.randint(min_val_xy, max_val_xy + 1)
168    point2Y = random.randint(min_val_xy, max_val_xy + 1)
169
170    distanceSq = (point1X - point2X)**2 + (point1Y - point2Y)**2
171
172    solution = rf"$\sqrt{{{distanceSq}}}$"
173    problem = f"Find the distance between $({point1X}, {point1Y})$ and $({point2X}, {point2Y})$"
174    return problem, solution

Distance between 2 points

Ex. Problem Ex. Solution
Find the distance between $(-19, -6)$ and $(15, -16)$ $\sqrt{1256}$
def expanding(range_x1=10, range_x2=10, range_a=10, range_b=10):
177def expanding(range_x1=10, range_x2=10, range_a=10, range_b=10):
178    r"""Expanding Factored Binomial
179
180    | Ex. Problem | Ex. Solution |
181    | --- | --- |
182    |$(x-6)(-3x-3)$ | $x^2+18x+18$ |
183    """
184    x1 = random.randint(-range_x1, range_x1)
185    x2 = random.randint(-range_x2, range_x2)
186    a = random.randint(-range_a, range_a)
187    b = random.randint(-range_b, range_b)
188
189    def intParser(z):
190        if (z > 0):
191            return f"+{z}"
192        elif (z < 0):
193            return f"-{abs(z)}"
194        else:
195            return ""
196
197    c1 = intParser(a * b)
198    c2 = intParser((a * x2) + (b * x1))
199    c3 = intParser(x1 * x2)
200
201    p1 = intParser(a)
202    p2 = intParser(x1)
203    p3 = intParser(b)
204    p4 = intParser(x2)
205
206    if p1 == "+1":
207        p1 = ""
208    elif len(p1) > 0 and p1[0] == "+":
209        p1 = p1[1:]
210    if p3 == "+1":
211        p3 = ""
212    elif p3[0] == "+":
213        p3 = p3[1:]
214
215    if c1 == "+1":
216        c1 = ""
217    elif len(c1) > 0 and c1[0] == "+":
218        c1 = c1[1:]  # Cuts off the plus for readability
219    if c2 == "+1":
220        c2 = ""
221
222    problem = f"$({p1}x{p2})({p3}x{p4})$"
223    solution = f"${c1}x^2{c2}x{c3}$"
224    return problem, solution

Expanding Factored Binomial

Ex. Problem Ex. Solution
$(x-6)(-3x-3)$ $x^2+18x+18$
def factoring(range_x1=10, range_x2=10):
227def factoring(range_x1=10, range_x2=10):
228    r"""Factoring Quadratic
229    Given a quadratic equation in the form x^2 + bx + c, factor it into it's roots (x - x1)(x -x2)
230
231    | Ex. Problem | Ex. Solution |
232    | --- | --- |
233    | $x^2+2x-24$ | $(x-4)(x+6)$ |
234    """
235    x1 = random.randint(-range_x1, range_x1)
236    x2 = random.randint(-range_x2, range_x2)
237
238    def intParser(z):
239        if (z > 0):
240            return f"+{z}"
241        elif (z < 0):
242            return f"-{abs(z)}"
243        else:
244            return ""
245
246    b = intParser(x1 + x2)
247    c = intParser(x1 * x2)
248
249    if b == "+1":
250        b = "+"
251    if b == "":
252        problem = f"x^2{c}"
253    else:
254        problem = f"x^2{b}x{c}"
255
256    x1 = intParser(x1)
257    x2 = intParser(x2)
258    solution = f"$(x{x1})(x{x2})$"
259    return f"${problem}$", solution

Factoring Quadratic Given a quadratic equation in the form x^2 + bx + c, factor it into it's roots (x - x1)(x -x2)

Ex. Problem Ex. Solution
$x^2+2x-24$ $(x-4)(x+6)$
def int_matrix_22_determinant(max_matrix_val=100):
262def int_matrix_22_determinant(max_matrix_val=100):
263    r"""Determinant to 2x2 Matrix
264
265    | Ex. Problem | Ex. Solution |
266    | --- | --- |
267    | $\det \begin{bmatrix} 88 & 40 \\\ 9 & 91 \end{bmatrix}= $ | $7648$ |
268    """
269    a = random.randint(0, max_matrix_val)
270    b = random.randint(0, max_matrix_val)
271    c = random.randint(0, max_matrix_val)
272    d = random.randint(0, max_matrix_val)
273
274    determinant = a * d - b * c
275    lst = [[a, b], [c, d]]
276
277    problem = rf"$\det {bmatrix(lst)}= $"
278    solution = f"${determinant}$"
279    return problem, solution

Determinant to 2x2 Matrix

Ex. Problem Ex. Solution
$\det \begin{bmatrix} 88 & 40 \\ 9 & 91 \end{bmatrix}= $ $7648$
def intersection_of_two_lines( min_m=-10, max_m=10, min_b=-10, max_b=10, min_denominator=1, max_denominator=6):
282def intersection_of_two_lines(min_m=-10,
283                              max_m=10,
284                              min_b=-10,
285                              max_b=10,
286                              min_denominator=1,
287                              max_denominator=6):
288    r"""Intersection of two lines
289
290    | Ex. Problem | Ex. Solution |
291    | --- | --- |
292    | Find the point of intersection of the two lines: $y = \frac{-2}{6}x + 3$ and $y = \frac{3}{6}x - 8$ | $(\frac{66}{5}, \frac{-7}{5})$ |
293    """
294    def generateEquationString(m, b):
295        """
296        Generates an equation given the slope and intercept.
297        It handles cases where m is fractional.
298        It also ensures that we don't have weird signs such as y = mx + -b.
299        """
300        if m[0] == 0:
301            m = 0
302        elif abs(m[0]) == abs(m[1]):
303            m = m[0] // m[1]
304        elif m[1] == 1:
305            m = m[0]
306        else:
307            m = rf"\frac{{{m[0]}}}{{{m[1]}}}"
308        base = "y ="
309        if m != 0:
310            if m == 1:
311                base = f"{base} x"
312            elif m == -1:
313                base = f"{base} -x"
314            else:
315                base = f"{base} {m}x"
316        if b > 0:
317            if m == 0:
318                return f"{base} {b}"
319            else:
320                return f"{base} + {b}"
321        elif b < 0:
322            if m == 0:
323                return f"{base} -{b * -1}"
324            else:
325                return f"{base} - {b * -1}"
326        else:
327            if m == 0:
328                return f"{base} 0"
329            else:
330                return base
331
332    def fractionToString(x):
333        """
334        Converts the given fractions.Fraction into a string.
335        """
336        if x.denominator == 1:
337            x = x.numerator
338        else:
339            x = rf"\frac{{{x.numerator}}}{{{x.denominator}}}"
340        return x
341
342    m1 = (random.randint(min_m, max_m),
343          random.randint(min_denominator, max_denominator))
344    m2 = (random.randint(min_m, max_m),
345          random.randint(min_denominator, max_denominator))
346
347    b1 = random.randint(min_b, max_b)
348    b2 = random.randint(min_b, max_b)
349
350    eq1 = generateEquationString(m1, b1)
351    eq2 = generateEquationString(m2, b2)
352
353    problem = f"Find the point of intersection of the two lines: ${eq1}$ and ${eq2}$"
354
355    m1 = fractions.Fraction(*m1)
356    m2 = fractions.Fraction(*m2)
357    # if m1 == m2 then the slopes are equal
358    # This can happen if both line are the same
359    # Or if they are parallel
360    # In either case there is no intersection
361
362    if m1 == m2:
363        solution = "No Solution"
364    else:
365        intersection_x = (b1 - b2) / (m2 - m1)
366        intersection_y = ((m2 * b1) - (m1 * b2)) / (m2 - m1)
367        solution = f"$({fractionToString(intersection_x)}, {fractionToString(intersection_y)})$"
368
369    return problem, solution

Intersection of two lines

Ex. Problem Ex. Solution
Find the point of intersection of the two lines: $y = \frac{-2}{6}x + 3$ and $y = \frac{3}{6}x - 8$ $(\frac{66}{5}, \frac{-7}{5})$
def invert_matrix( square_matrix_dimension=3, max_matrix_element=99, only_integer_elements_in_inverted_matrixe=True):
372def invert_matrix(square_matrix_dimension=3,
373                  max_matrix_element=99,
374                  only_integer_elements_in_inverted_matrixe=True):
375    r"""Invert Matrix
376
377    | Ex. Problem | Ex. Solution |
378    | --- | --- |
379    | Inverse of Matrix $\begin{bmatrix} 4 & 1 & 4 \\\ 5 & 1 & 5 \\\ 12 & 3 & 13 \end{bmatrix}$ is: | $\begin{bmatrix} 2 & 1 & -1 \\\ 5 & -4 & 0 \\\ -3 & 0 & 1 \end{bmatrix}$ |
380    """
381    if only_integer_elements_in_inverted_matrixe is True:
382        isItOk = False
383        Mat = list()
384        while (isItOk is False):
385            Mat = list()
386            for i in range(0, square_matrix_dimension):
387                z = list()
388                for j in range(0, square_matrix_dimension):
389                    z.append(0)
390                z[i] = 1
391                Mat.append(z)
392            MaxAllowedMatrixElement = math.ceil(
393                pow(max_matrix_element, 1 / (square_matrix_dimension)))
394            randomlist = random.sample(range(0, MaxAllowedMatrixElement + 1),
395                                       square_matrix_dimension)
396
397            for i in range(0, square_matrix_dimension):
398                if i == square_matrix_dimension - 1:
399                    Mat[0] = [
400                        j + (k * randomlist[i])
401                        for j, k in zip(Mat[0], Mat[i])
402                    ]
403                else:
404                    Mat[i + 1] = [
405                        j + (k * randomlist[i])
406                        for j, k in zip(Mat[i + 1], Mat[i])
407                    ]
408
409            for i in range(1, square_matrix_dimension - 1):
410                Mat[i] = [
411                    sum(i)
412                    for i in zip(Mat[square_matrix_dimension - 1], Mat[i])
413                ]
414
415            isItOk = True
416            for i in Mat:
417                for j in i:
418                    if j > max_matrix_element:
419                        isItOk = False
420                        break
421                if isItOk is False:
422                    break
423
424        random.shuffle(Mat)
425        Mat = sympy.Matrix(Mat)
426        Mat = sympy.Matrix.transpose(Mat)
427        Mat = Mat.tolist()
428        random.shuffle(Mat)
429        Mat = sympy.Matrix(Mat)
430        Mat = sympy.Matrix.transpose(Mat)
431
432    else:
433        randomlist = list(sympy.primerange(0, max_matrix_element + 1))
434        plist = random.sample(randomlist, square_matrix_dimension)
435        randomlist = random.sample(
436            range(0, max_matrix_element + 1),
437            square_matrix_dimension * square_matrix_dimension)
438        randomlist = list(set(randomlist) - set(plist))
439        n_list = random.sample(
440            randomlist,
441            square_matrix_dimension * (square_matrix_dimension - 1))
442        Mat = list()
443        for i in range(0, square_matrix_dimension):
444            z = list()
445            z.append(plist[i])
446            for j in range(0, square_matrix_dimension - 1):
447                z.append(n_list[(i * square_matrix_dimension) + j - i])
448            random.shuffle(z)
449            Mat.append(z)
450        Mat = sympy.Matrix(Mat)
451
452    problem = 'Inverse of Matrix $' + bmatrix(Mat.tolist()) + '$ is:'
453    solution = f'${bmatrix(sympy.Matrix.inv(Mat).tolist())}$'
454    return problem, solution

Invert Matrix

Ex. Problem Ex. Solution
Inverse of Matrix $\begin{bmatrix} 4 & 1 & 4 \\ 5 & 1 & 5 \\ 12 & 3 & 13 \end{bmatrix}$ is: $\begin{bmatrix} 2 & 1 & -1 \\ 5 & -4 & 0 \\ -3 & 0 & 1 \end{bmatrix}$
def linear_equations(n=2, var_range=20, coeff_range=20):
457def linear_equations(n=2, var_range=20, coeff_range=20):
458    r"""Linear Equations
459
460    | Ex. Problem | Ex. Solution |
461    | --- | --- |
462    | Given the equations $10x + -20y = 310$ and $-16x + -17y = 141$, solve for $x$ and $y$ | $x = 5$, $y = -13$ |
463    """
464    if n > 10:
465        print("[!] n cannot be greater than 10")
466        return None, None
467
468    vars = ['x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g'][:n]
469    soln = [random.randint(-var_range, var_range) for i in range(n)]
470    problem = list()
471    solution = "$, $".join(
472        ["{} = {}".format(vars[i], soln[i]) for i in range(n)])
473
474    for _ in range(n):
475        coeff = [random.randint(-coeff_range, coeff_range) for i in range(n)]
476        res = sum([coeff[i] * soln[i] for i in range(n)])
477        prob = [
478            "{}{}".format(coeff[i], vars[i]) if coeff[i] != 0 else ""
479            for i in range(n)
480        ]
481
482        while "" in prob:
483            prob.remove("")
484        prob = " + ".join(prob) + " = " + str(res)
485        problem.append(prob)
486
487    # problem = "\n".join(problem)
488    problem = "$ and $".join(problem)
489
490    return f'Given the equations ${problem}$, solve for $x$ and $y$', f'${solution}$'

Linear Equations

Ex. Problem Ex. Solution
Given the equations $10x + -20y = 310$ and $-16x + -17y = 141$, solve for $x$ and $y$ $x = 5$, $y = -13$
def line_equation_from_2_points(max_val=20):
493def line_equation_from_2_points(max_val=20):
494    r"""Equation of Line from Two Points
495
496    | Ex. Problem | Ex. Solution |
497    | --- | --- |
498    | Find the equation of the line passing through the points $(-19,-8)$ and $(-2,0)$. | $y=\frac{8}{17}x+\frac{16}{17}$ |
499    """
500    x1 = random.randint(-max_val, max_val)
501    x2 = random.randint(-max_val, max_val)
502    if x1 == x2:
503        return line_equation_from_2_points(max_val=max_val)
504    y1 = random.randint(-max_val, max_val)
505    y2 = random.randint(-max_val, max_val)
506    m1 = (y2 - y1) // math.gcd(y2 - y1, x2 - x1)
507    m2 = (x2 - x1) // math.gcd(y2 - y1, x2 - x1)
508    c1 = (y1 * (x2 - x1) - (y2 - y1) * x1) // math.gcd(y1 * (x2 - x1) - (y2 - y1) * x1, (x2 - x1))
509    c2 = (x2 - x1) // math.gcd(y1 * (x2 - x1) - (y2 - y1) * x1, (x2 - x1))
510    c = rf"{'+' if c1 >= 0 else '-'}\frac{{{abs(c1)}}}{{{c2}}}" if c1 != 0 else ""
511    if c2 < 0:
512        c2 = -c2
513        c1 = -c1
514        c = rf"{'+' if c1 >= 0 else '-'}\frac{{{abs(c1)}}}{{{c2}}}"
515    if c2 == 1:
516        c = f"{c1:+}"
517
518    problem = f'Find the equation of the line passing through the points $({x1},{y1})$ and $({x2},{y2})$.'
519
520    if m1 == 0:
521        return problem, f"$y={c}$"
522    if m2 < 0:
523        m1 = -m1
524        m2 = -m2
525    if m2 == 1:
526        if m1 == 1:
527            return problem, f"$y=x{c}$"
528        if m1 == -1:
529            return problem, f"$y=-x{c}$"
530        return problem, f"y={m1}x{c}"
531
532    return problem, rf"$y=\frac{{{m1}}}{{{m2}}}x{c}$"

Equation of Line from Two Points

Ex. Problem Ex. Solution
Find the equation of the line passing through the points $(-19,-8)$ and $(-2,0)$. $y=\frac{8}{17}x+\frac{16}{17}$
def log(max_base=3, max_val=8):
535def log(max_base=3, max_val=8):
536    r"""Logarithm
537
538    | Ex. Problem | Ex. Solution |
539    | --- | --- |
540    | $log_{3}(243)=$ | $5$ |
541    """
542    a = random.randint(1, max_val)
543    b = random.randint(2, max_base)
544    c = pow(b, a)
545
546    problem = f'$log_{{{b}}}({c})=$'
547    solution = f'${a}$'
548    return problem, solution

Logarithm

Ex. Problem Ex. Solution
$log_{3}(243)=$ $5$
def matrix_multiplication(max_val=100, max_dim=10):
551def matrix_multiplication(max_val=100, max_dim=10):
552    r"""Multiply Two Matrices
553
554    | Ex. Problem | Ex. Solution |
555    | --- | --- |
556    | Multiply $\begin{bmatrix} 15 & 72 \\\ 64 & -20 \\\ 18 & 59 \\\ -21 & -55 \\\ 20 & -12 \\\ -75 & -42 \\\ 47 & 89 \\\ -53 & 27 \\\ -56 & 44 \end{bmatrix}$ and $\begin{bmatrix} 49 & -2 & 68 & -28 \\\ 49 & 6 & 83 & 42 \end{bmatrix}$ | $\begin{bmatrix} 4263 & 402 & 6996 & 2604 \\\ 2156 & -248 & 2692 & -2632 \\\ 3773 & 318 & 6121 & 1974 \\\ -3724 & -288 & -5993 & -1722 \\\ 392 & -112 & 364 & -1064 \\\ -5733 & -102 & -8586 & 336 \\\ 6664 & 440 & 10583 & 2422 \\\ -1274 & 268 & -1363 & 2618 \\\ -588 & 376 & -156 & 3416 \end{bmatrix}$ |
557    """
558    m = random.randint(2, max_dim)
559    n = random.randint(2, max_dim)
560    k = random.randint(2, max_dim)
561
562    # generate matrices a and b
563    a = [[random.randint(-max_val, max_val) for _ in range(n)]
564         for _ in range(m)]
565    b = [[random.randint(-max_val, max_val) for _ in range(k)]
566         for _ in range(n)]
567
568    res = []
569    for r in range(m):
570        res.append([])
571        for c in range(k):
572            temp = 0
573            for t in range(n):
574                temp += a[r][t] * b[t][c]
575            res[r].append(temp)
576
577    problem = f"Multiply ${bmatrix(a)}$ and ${bmatrix(b)}$"
578    solution = f'${bmatrix(res)}$'
579    return problem, solution

Multiply Two Matrices

Ex. Problem Ex. Solution
Multiply $\begin{bmatrix} 15 & 72 \\ 64 & -20 \\ 18 & 59 \\ -21 & -55 \\ 20 & -12 \\ -75 & -42 \\ 47 & 89 \\ -53 & 27 \\ -56 & 44 \end{bmatrix}$ and $\begin{bmatrix} 49 & -2 & 68 & -28 \\ 49 & 6 & 83 & 42 \end{bmatrix}$ $\begin{bmatrix} 4263 & 402 & 6996 & 2604 \\ 2156 & -248 & 2692 & -2632 \\ 3773 & 318 & 6121 & 1974 \\ -3724 & -288 & -5993 & -1722 \\ 392 & -112 & 364 & -1064 \\ -5733 & -102 & -8586 & 336 \\ 6664 & 440 & 10583 & 2422 \\ -1274 & 268 & -1363 & 2618 \\ -588 & 376 & -156 & 3416 \end{bmatrix}$
def midpoint_of_two_points(max_value=20):
582def midpoint_of_two_points(max_value=20):
583    r"""Midpoint of two points
584
585    | Ex. Problem | Ex. Solution |
586    | --- | --- |
587    | The midpoint of $(-8,10)$ and $(18,0) = $ | $(5.0,5.0)$ |
588    """
589    x1 = random.randint(-20, max_value)
590    y1 = random.randint(-20, max_value)
591    x2 = random.randint(-20, max_value)
592    y2 = random.randint(-20, max_value)
593    xm = (x1 + x2) / 2
594    ym = (y1 + y2) / 2
595
596    problem = f"The midpoint of $({x1},{y1})$ and $({x2},{y2}) = $"
597    solution = f"$({xm},{ym})$"
598    return problem, solution

Midpoint of two points

Ex. Problem Ex. Solution
The midpoint of $(-8,10)$ and $(18,0) = $ $(5.0,5.0)$
def multiply_complex_numbers(min_real_imaginary_num=-20, max_real_imaginary_num=20):
601def multiply_complex_numbers(min_real_imaginary_num=-20,
602                             max_real_imaginary_num=20):
603    r"""Multiplication of 2 complex numbers
604
605    | Ex. Problem | Ex. Solution |
606    | --- | --- |
607    | $(14+18j) * (14+15j) = $ | $(-74+462j)$ |
608    """
609    num1 = complex(
610        random.randint(min_real_imaginary_num, max_real_imaginary_num),
611        random.randint(min_real_imaginary_num, max_real_imaginary_num))
612    num2 = complex(
613        random.randint(min_real_imaginary_num, max_real_imaginary_num),
614        random.randint(min_real_imaginary_num, max_real_imaginary_num))
615    product = num1 * num2
616
617    problem = f"${num1} * {num2} = $"
618    solution = f'${product}$'
619    return problem, solution

Multiplication of 2 complex numbers

Ex. Problem Ex. Solution
$(14+18j) * (14+15j) = $ $(-74+462j)$
def multiply_int_to_22_matrix(max_matrix_val=10, max_res=100):
622def multiply_int_to_22_matrix(max_matrix_val=10, max_res=100):
623    r"""Multiply Integer to 2x2 Matrix
624
625    | Ex. Problem | Ex. Solution |
626    | --- | --- |
627    | $5 * \begin{bmatrix} 1 & 0 \\\ 2 & 9 \end{bmatrix} =$ | $\begin{bmatrix} 5 & 0 \\\ 10 & 45 \end{bmatrix}$ |
628    """
629    a = random.randint(0, max_matrix_val)
630    b = random.randint(0, max_matrix_val)
631    c = random.randint(0, max_matrix_val)
632    d = random.randint(0, max_matrix_val)
633
634    constant = random.randint(0, int(max_res / max(a, b, c, d)))
635
636    a1 = a * constant
637    b1 = b * constant
638    c1 = c * constant
639    d1 = d * constant
640    lst = [[a, b], [c, d]]
641    lst1 = [[a1, b1], [c1, d1]]
642
643    problem = f'${constant} * {bmatrix(lst)} =$'
644    solution = f'${bmatrix(lst1)}$'
645    return problem, solution

Multiply Integer to 2x2 Matrix

Ex. Problem Ex. Solution
$5 * \begin{bmatrix} 1 & 0 \\ 2 & 9 \end{bmatrix} =$ $\begin{bmatrix} 5 & 0 \\ 10 & 45 \end{bmatrix}$
def quadratic_equation(max_val=100):
648def quadratic_equation(max_val=100):
649    r"""Quadratic Equation
650
651    | Ex. Problem | Ex. Solution |
652    | --- | --- |
653    | What are the zeros of the quadratic equation $22x^2+137x+25=0$ | ${-0.19, -6.04}$ |
654    """
655    a = random.randint(1, max_val)
656    c = random.randint(1, max_val)
657    b = random.randint(
658        round(math.sqrt(4 * a * c)) + 1,
659        round(math.sqrt(4 * max_val * max_val)))
660    D = math.sqrt(b * b - 4 * a * c)
661    res = {round((-b + D) / (2 * a), 2), round((-b - D) / (2 * a), 2)}
662
663    problem = f"What are the zeros of the quadratic equation ${a}x^2+{b}x+{c}=0$"
664    solution = f'${res}$'
665    return problem, solution

Quadratic Equation

Ex. Problem Ex. Solution
What are the zeros of the quadratic equation $22x^2+137x+25=0$ ${-0.19, -6.04}$
def simple_interest(max_principle=10000, max_rate=10, max_time=10):
668def simple_interest(max_principle=10000, max_rate=10, max_time=10):
669    r"""Simple Interest
670
671    | Ex. Problem | Ex. Solution |
672    | --- | --- |
673    | Simple interest for a principle amount of $7217$ dollars, $3$% rate of interest and for a time period of $10$ years is $=$ | $2165.1$ |
674    """
675    p = random.randint(1000, max_principle)
676    r = random.randint(1, max_rate)
677    t = random.randint(1, max_time)
678    s = round((p * r * t) / 100, 2)
679
680    problem = f"Simple interest for a principle amount of ${p}$ dollars, ${r}$% rate of interest and for a time period of ${t}$ years is $=$ "
681    solution = f'${s}$'
682    return problem, solution

Simple Interest

Ex. Problem Ex. Solution
Simple interest for a principle amount of $7217$ dollars, $3$% rate of interest and for a time period of $10$ years is $=$ $2165.1$
def system_of_equations(range_x=10, range_y=10, coeff_mult_range=10):
685def system_of_equations(range_x=10, range_y=10, coeff_mult_range=10):
686    r"""Solve a System of Equations in R^2
687
688    | Ex. Problem | Ex. Solution |
689    | --- | --- |
690    | Given $-x + 5y = -28$ and $9x + 2y = 64$, solve for $x$ and $y$. | $x = 8$, $y = -4$ |
691    """
692    # Generate solution point first
693    x = random.randint(-range_x, range_x)
694    y = random.randint(-range_y, range_y)
695    # Start from reduced echelon form (coeffs 1)
696    c1 = [1, 0, x]
697    c2 = [0, 1, y]
698
699    def randNonZero():
700        return random.choice(
701            [i for i in range(-coeff_mult_range, coeff_mult_range) if i != 0])
702
703    # Add random (non-zero) multiple of equations (rows) to each other
704    c1_mult = randNonZero()
705    c2_mult = randNonZero()
706    new_c1 = [c1[i] + c1_mult * c2[i] for i in range(len(c1))]
707    new_c2 = [c2[i] + c2_mult * c1[i] for i in range(len(c2))]
708    # For extra randomness, now add random (non-zero) multiples of original rows
709    # to themselves
710    c1_mult = randNonZero()
711    c2_mult = randNonZero()
712    new_c1 = [new_c1[i] + c1_mult * c1[i] for i in range(len(c1))]
713    new_c2 = [new_c2[i] + c2_mult * c2[i] for i in range(len(c2))]
714
715    def coeffToFuncString(coeffs):
716        # lots of edge cases for perfect formatting!
717        x_sign = '-' if coeffs[0] < 0 else ''
718        # No redundant 1s
719        x_coeff = str(abs(coeffs[0])) if abs(coeffs[0]) != 1 else ''
720        # If x coeff is 0, dont include x
721        x_str = f'{x_sign}{x_coeff}x' if coeffs[0] != 0 else ''
722        # if x isn't included and y is positive, dont include operator
723        op = ' - ' if coeffs[1] < 0 else (' + ' if x_str != '' else '')
724        # No redundant 1s
725        y_coeff = abs(coeffs[1]) if abs(coeffs[1]) != 1 else ''
726        # Don't include if 0, unless x is also 0 (probably never happens)
727        y_str = f'{y_coeff}y' if coeffs[1] != 0 else (
728            '' if x_str != '' else '0')
729        return f'{x_str}{op}{y_str} = {coeffs[2]}'
730
731    problem = f"Given ${coeffToFuncString(new_c1)}$ and ${coeffToFuncString(new_c2)}$, solve for $x$ and $y$."
732    solution = f"$x = {x}$, $y = {y}$"
733    return problem, solution
734    # Add random (non-zero) multiple of equations to each other

Solve a System of Equations in R^2

Ex. Problem Ex. Solution
Given $-x + 5y = -28$ and $9x + 2y = 64$, solve for $x$ and $y$. $x = 8$, $y = -4$
def vector_cross(min_val=-20, max_val=20):
737def vector_cross(min_val=-20, max_val=20):
738    r"""Cross product of 2 vectors
739
740    | Ex. Problem | Ex. Solution |
741    | --- | --- |
742    | $[-1, -4, 10] \times [-11, 1, -16] = $ | $[54, -126, -45]$ |
743    """
744    a = [random.randint(min_val, max_val) for _ in range(3)]
745    b = [random.randint(min_val, max_val) for _ in range(3)]
746    c = [
747        a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2],
748        a[0] * b[1] - a[1] * b[0]
749    ]
750
751    problem = rf"${a} \times {b} = $"
752    solution = f"${c}$"
753    return problem, solution

Cross product of 2 vectors

Ex. Problem Ex. Solution
$[-1, -4, 10] \times [-11, 1, -16] = $ $[54, -126, -45]$
def vector_dot(min_val=-20, max_val=20):
756def vector_dot(min_val=-20, max_val=20):
757    r"""Dot product of 2 vectors
758
759    | Ex. Problem | Ex. Solution |
760    | --- | --- |
761    | $[12, -9, -8]\cdot[-9, 8, 1]=$ | $-188$ |
762    """
763    a = [random.randint(min_val, max_val) for i in range(3)]
764    b = [random.randint(min_val, max_val) for i in range(3)]
765    c = a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
766
767    problem = rf'${a}\cdot{b}=$'
768    solution = f'${c}$'
769    return problem, solution

Dot product of 2 vectors

Ex. Problem Ex. Solution
$[12, -9, -8]\cdot[-9, 8, 1]=$ $-188$
def orthogonal_projection(min_val=-10, max_val=10):
772def orthogonal_projection(min_val=-10, max_val=10):
773    r"""Orthogonal Projection
774
775    | Ex. Problem | Ex. Solution |
776    | --- | --- |
777    | Find the orthogonal projection of $[2, 3]$ onto $[4, -7]$ | $[\frac{-4}{5}, \frac{7}{5}]$ |
778    """
779    v = [random.randint(min_val, max_val) for _ in range(2)]
780    u = [random.randint(min_val, max_val) for _ in range(2)]
781    dot_t = v[0] * u[0] + v[1] * u[1]
782    dot_b = u[0] * u[0] + u[1] * u[1]
783    frac = fractions.Fraction(dot_t, dot_b).limit_denominator()
784    y = [frac * u[0], frac * u[1]]
785
786    if y[0].denominator != 1:
787        y[0] = rf'\frac{{{y[0].numerator}}}{{{y[0].denominator}}}'
788    if y[1].denominator != 1:
789        y[1] = rf'\frac{{{y[1].numerator}}}{{{y[1].denominator}}}'
790
791    problem = f'Find the orthogonal projection of ${v}$ onto ${u}$'
792    solution = f'$[{y[0]}, {y[1]}]$'
793    return problem, solution

Orthogonal Projection

Ex. Problem Ex. Solution
Find the orthogonal projection of $[2, 3]$ onto $[4, -7]$ $[\frac{-4}{5}, \frac{7}{5}]$