2. Check solutions to equations: 1 step diagrams

The python file to make a check_solution 1-step diagram is below.
The 2 custom python modules required are:
The python file, check_solution_diagram_maker.py, when run, will ask for these inputs:
Choose the arithmetic process:
"Enter 1, 2, 3, 4 or 5 for +, -, X, /, random"
Choose the file name base:
""Enter the base filename to be added to the prefix check_solution1_:"
The filename will have β€œ_q” added for the question diagram and β€œ_ans” for the answer diagram.

2.1. Example check solution 1-step diagrams

question

answer

question

answer

question

answer

question

answer


2.2. Check solution diagram: python

  1from pathlib import Path
  2import subprocess
  3import os
  4import time
  5import magick_pdf_to_png
  6import check_solution_functions as chsolf
  7
  8
  9currfile_dir = Path(__file__).parent
 10tex_template_path = currfile_dir / "check_solution_template.tex"
 11texans_template_path = currfile_dir / "check_solution_template.tex"
 12tex_diagram_template_path = currfile_dir / "check_solution_diagram_template.tex"
 13
 14
 15def convert_to_pdf(tex_path, outputdir):
 16    tex_path = Path(tex_path).resolve()
 17    outputdir = Path(outputdir).resolve()
 18    # for testing
 19    # print(f"tex_path: {tex_path}")
 20    # print(f"outputdir: {outputdir}")
 21    try:
 22        # Generate the PDF
 23        subprocess.run(["latexmk", "-pdf", "-outdir=" + str(outputdir), str(tex_path)], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 24        # # Clean auxiliary files after successful PDF generation
 25        subprocess.run(["latexmk", "-c", "-outdir=" + str(outputdir), str(tex_path)], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 26        # for hosted remove stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL for debugging any errors
 27        # Remove the .tex file manually
 28        if tex_path.exists():
 29            os.remove(tex_path)
 30    except subprocess.CalledProcessError as e:
 31        print(f"Error: {e}")
 32
 33
 34# % end modify values for check_solution
 35# tex_keys = []
 36tex_keys_q = ["LHS", "LHSsub", "LHSval", "RHS", "side_equality", "is_a_sol"]
 37
 38
 39def make1_diagram(tex_diagram_template_txt, num):
 40    tex_diagram_template_txt_ans = tex_diagram_template_txt
 41    kv = chsolf.get_1step_process_dict(num)
 42    for key, value in kv.items():
 43        tex_diagram_template_txt_ans = tex_diagram_template_txt_ans.replace("<<" + key + ">>", value)
 44    for key, value in kv.items():
 45        if key not in tex_keys_q:
 46            tex_diagram_template_txt = tex_diagram_template_txt.replace("<<" + key + ">>", value)
 47        else:
 48            tex_diagram_template_txt = tex_diagram_template_txt.replace("<<" + key + ">>", kv[f"{key}q"])
 49    return tex_diagram_template_txt, tex_diagram_template_txt_ans
 50
 51
 52def main():
 53    num = input("Enter 1, 2, 3, 4 or 5 for +, -, X, /, random \n")
 54    if num.strip().isdigit():
 55        num = int(num)
 56        if not num in [1, 2, 3, 4, 5]:
 57            num = 5  # random by default
 58    else:
 59        num = 5  # random by default
 60    filename = input("Enter the base filename to be added to the prefix check_solution1_: \n")
 61    if not filename:
 62        filename = "1"  # "check_solution1_1_q and check_solution1_1_ans as default file"
 63    # set names of files that are made
 64    # questions
 65    tex_output_path = currfile_dir / f"check_solution1_{filename}_q.tex"
 66    pdf_path = currfile_dir / f"check_solution1_{filename}_q.pdf"
 67    png_path = currfile_dir / f"check_solution1_{filename}_q.png"
 68
 69    # answers
 70    tex_output_path_ans = currfile_dir / f"check_solution1_{filename}_ans.tex"
 71    pdf_path_ans = currfile_dir / f"check_solution1_{filename}_ans.pdf"
 72    png_path_ans = currfile_dir / f"check_solution1_{filename}_ans.png"
 73
 74    # Read in the LaTeX template file
 75    with open(tex_template_path, "r") as infile:
 76        tex_template_txt = infile.read()
 77    # Read in the LaTeX template file for answers
 78    with open(texans_template_path, "r") as infile:
 79        tex_template_txt_ans = infile.read()
 80    # Read in the LaTeX diagram template file
 81    with open(tex_diagram_template_path, "r") as infile:
 82        tex_diagram_template_txt = infile.read()
 83
 84    # Generate the <<diagram>> replacement tex
 85    diagram_text, diagram_text_ans = make1_diagram(tex_diagram_template_txt, num)
 86    # Replace the <<diagram>> placeholder in the LaTeX template
 87    tex_template_txt = tex_template_txt.replace("<<diagram>>", diagram_text)
 88    tex_template_txt_ans = tex_template_txt_ans.replace("<<diagram>>", diagram_text_ans)
 89    # Write the question diagram tex to an output file
 90    with open(tex_output_path, "w") as outfile:
 91        outfile.write(tex_template_txt)
 92    # Write the answer diagram tex to an output file
 93    with open(tex_output_path_ans, "w") as outfile:
 94        outfile.write(tex_template_txt_ans)
 95
 96    # Wait for the files to be created
 97    time.sleep(1)
 98    # convert to pdf
 99    convert_to_pdf(tex_output_path, currfile_dir)
100    convert_to_pdf(tex_output_path_ans, currfile_dir)
101
102    # Wait for the files to be created
103    time.sleep(1)
104    # convert to png
105    magick_pdf_to_png.convert_pdf_to_png(pdf_path, png_path)
106    magick_pdf_to_png.convert_pdf_to_png(pdf_path_ans, png_path_ans)
107
108
109if __name__ == "__main__":
110    print("starting")
111    main()
112    print("finished")
The custom python module:
  1"""
  2Module of functions to return diagram dictionary for LaTeX
  3# escape {} in f strings by doubling them up {{}}
  4"""
  5
  6import random
  7
  8
  9def get_offset():
 10    off_numbers = [-3, -2, -1, 1, 2, 3]
 11    return random.choice(off_numbers)
 12
 13
 14def get_1step_process_dict(num):
 15    if num is None or num == 5:
 16        num = random.randint(1, 4)
 17    match num:
 18        case 1:
 19            return add_dict()
 20        case 2:
 21            return sub_dict()
 22        case 3:
 23            return times_dict()
 24        case 4:
 25            return div_dict()
 26
 27
 28def add_dict():
 29    # x + nx = na
 30    # xsol = x; xval is test val
 31    nx = random.randint(1, 10)
 32    na = random.randint(1, 10)
 33    xsol = na - nx
 34    #
 35    kv = dict()
 36    if random.randint(1, 10) > 6:
 37        xval = xsol + get_offset()
 38        kv["side_equality"] = r"\neq"
 39        kv["is_a_sol"] = "is not "
 40    else:
 41        xval = xsol
 42        kv["side_equality"] = "="
 43        kv["is_a_sol"] = "is "
 44    #
 45    kv["pro_value"] = f"x = {xval}"
 46    kv["equation"] = f"x + {nx} = {na}"
 47    kv["LHS"] = f"x + {nx}"
 48    kv["LHSsub"] = f"{xval} + {nx}"
 49    kv["LHSval"] = f"{xval + nx} "
 50    kv["LHSq"] = f""
 51    kv["LHSsubq"] = f""
 52    kv["LHSvalq"] = f""
 53    kv["RHS"] = f"{na}"
 54    kv["RHSq"] = f""
 55    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
 56    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
 57    return kv
 58
 59
 60"""
 61kv["pro_value"]   x=4
 62kv["equation"]  x + 5 = 9
 63kv["LHS"]
 64kv["LHSsub"]
 65kv["LHSval"]
 66
 67kv["side_equality"]
 68kv["is_a_sol"]
 69"""
 70
 71
 72def sub_dict():
 73    # x - nx = na
 74    # xsol = x; xval is test val
 75    nx = random.randint(1, 10)
 76    na = random.randint(1, 10)
 77    xsol = na + nx
 78    #
 79    kv = dict()
 80    if random.randint(1, 10) > 6:
 81        xval = xsol + get_offset()
 82        kv["side_equality"] = r"\neq"
 83        kv["is_a_sol"] = "is not "
 84    else:
 85        xval = xsol
 86        kv["side_equality"] = "="
 87        kv["is_a_sol"] = "is "
 88    #
 89    kv["pro_value"] = f"x = {xval}"
 90    kv["equation"] = f"x - {nx} = {na}"
 91    kv["LHS"] = f"x - {nx}"
 92    kv["LHSsub"] = f"{xval} - {nx}"
 93    kv["LHSval"] = f"{xval - nx} "
 94    kv["LHSq"] = f""
 95    kv["LHSsubq"] = f""
 96    kv["LHSvalq"] = f""
 97    kv["RHS"] = f"{na}"
 98    kv["RHSq"] = f""
 99    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
100    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
101    return kv
102
103
104def times_dict():
105    # xsol = x; xval is test val
106    # x * nx = na
107    nx = random.randint(2, 10)
108    xsol = random.randint(2, 10)
109    na = xsol * nx
110    #
111    kv = dict()
112    if random.randint(1, 10) > 6:
113        xval = xsol + get_offset()
114        kv["side_equality"] = r"\neq"
115        kv["is_a_sol"] = "is not "
116    else:
117        xval = xsol
118        kv["side_equality"] = "="
119        kv["is_a_sol"] = "is "
120    #
121    kv["pro_value"] = f"x = {xval}"
122    kv["equation"] = f"{nx}x = {na}"
123    kv["LHS"] = f"{nx}x"
124    kv["LHSsub"] = f"{nx} \\times{xval}"
125    kv["LHSval"] = f"{nx * xval} "
126    kv["LHSq"] = f""
127    kv["LHSsubq"] = f""
128    kv["LHSvalq"] = f""
129    kv["RHS"] = f"{na}"
130    kv["RHSq"] = f""
131    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
132    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
133    return kv
134
135
136def div_dict():
137    # xsol = x; xval is test val
138    # x / nx = na
139    nx = random.randint(2, 10)
140    na = random.randint(2, 10)
141    xsol = na * nx
142    #
143    kv = dict()
144    if random.randint(1, 10) > 6:
145        # offset a multiple such that
146        xval = xsol + (get_offset() * nx)
147        kv["side_equality"] = r"\neq"
148        kv["is_a_sol"] = "is not "
149        if xval % nx == 0:
150            xval_div_nx = int(xval / nx)
151        else:
152            xval_div_nx = round(xval / nx, 3)
153        kv["LHSval"] = f"{xval_div_nx}"
154    else:
155        xval = xsol
156        kv["side_equality"] = "="
157        kv["is_a_sol"] = "is "
158        kv["LHSval"] = f"{na}"  # to avoid ".0" for float
159    #
160    kv["pro_value"] = f"x = {xval}"
161    kv["equation"] = f"\\frac{{x}}{{{nx}}} = {na}"
162    kv["LHS"] = f"\\frac{{x}}{{{nx}}}"
163    kv["LHSsub"] = f"\\frac{{{xval}}}{{{nx}}}"
164    # kv["LHSval"] = f"{xval / nx}"  # see above
165    kv["LHSq"] = f""
166    kv["LHSsubq"] = f""
167    kv["LHSvalq"] = f""
168    kv["RHS"] = f"{na}"
169    kv["RHSq"] = f""
170    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
171    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
172    return kv
173
174
175# ############################################
176
177
178def val_in_list_exclude(low, high, exclude):
179    # random 2 step: avoid xx, x/, /x, //, ++, --, +-, -+
180    vals = list(range(low, high + 1))
181    if exclude in vals:
182        if exclude in [1, 2]:
183            vals.remove(1)
184            vals.remove(2)
185        elif exclude in [3, 4]:
186            vals.remove(3)
187            vals.remove(4)
188    return random.choice(vals)
189
190
191def get_2step_process_dict(num1, num2):
192    if num1 is None or num1 == 5:
193        num1 = random.randint(1, 4)
194    if num2 is None or num2 == 5:
195        num2 = random.randint(1, 4)
196        # num2 = val_in_list_exclude(1, 4, num1)
197    processes = (num1, num2)
198    # processes = (3,3)
199    match processes:
200        case (1, 1):
201            return add_add_dict()
202        case (1, 2):
203            return add_sub_dict()
204        case (1, 3):
205            return add_times_dict()
206        case (1, 4):
207            return add_div_dict()
208        case (2, 1):
209            return sub_add_dict()
210        case (2, 2):
211            return sub_sub_dict()
212        case (2, 3):
213            return sub_times_dict()
214        case (2, 4):
215            return sub_div_dict()
216        case (3, 1):
217            return times_add_dict()
218        case (3, 2):
219            return times_sub_dict()
220        case (3, 3):
221            return times_times_dict()
222        case (3, 4):
223            return times_div_dict()
224        case (4, 1):
225            return div_add_dict()
226        case (4, 2):
227            return div_sub_dict()
228        case (4, 3):
229            return div_times_dict()
230        case (4, 4):
231            return div_div_dict()
232        case _:
233            return add_add_dict()
234
235
236def add_add_dict():
237    # x + nx + mx = na
238    # xsol = x; xval is test val
239    nx = random.randint(1, 10)
240    mx = random.randint(1, 10)
241    na = random.randint(1, 10)
242    xsol = na - nx - mx
243    #
244    kv = dict()
245    if random.randint(1, 10) > 6:
246        xval = xsol + get_offset()
247        kv["side_equality"] = r"\neq"
248        kv["is_a_sol"] = "is not "
249    else:
250        xval = xsol
251        kv["side_equality"] = "="
252        kv["is_a_sol"] = "is "
253    #
254    kv["pro_value"] = f"x = {xval}"
255    kv["equation"] = f"x + {nx} + {mx} = {na}"
256    kv["LHS"] = f"x + {nx} + {mx}"
257    kv["LHSsub"] = f"{xval} + {nx} + {mx}"
258    kv["LHSval"] = f"{xval + nx + mx} "
259    kv["LHSq"] = f""
260    kv["LHSsubq"] = f""
261    kv["LHSvalq"] = f""
262    kv["RHS"] = f"{na}"
263    kv["RHSq"] = f""
264    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
265    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
266    return kv
267
268
269def add_sub_dict():
270    # bc = nx + na - nb
271    nx = random.randint(1, 10)
272    na = random.randint(1, 10)
273    bb = nx + na
274    if bb > 10:
275        nb = random.randint(1, 10)
276    else:
277        nb = random.randint(1, bb)
278    bc = bb - nb
279
280    # x + nx - mx = na
281    # xsol = x; xval is test val
282    nx = random.randint(1, 10)
283    mx = random.randint(1, 10)
284    na = random.randint(1, 10)
285    xsol = na - nx + mx
286    #
287    kv = dict()
288    if random.randint(1, 10) > 6:
289        xval = xsol + get_offset()
290        kv["side_equality"] = r"\neq"
291        kv["is_a_sol"] = "is not "
292    else:
293        xval = xsol
294        kv["side_equality"] = "="
295        kv["is_a_sol"] = "is "
296    #
297    kv["pro_value"] = f"x = {xval}"
298    kv["equation"] = f"x + {nx} - {mx} = {na}"
299    kv["LHS"] = f"x + {nx} - {mx}"
300    kv["LHSsub"] = f"{xval} + {nx} - {mx}"
301    kv["LHSval"] = f"{xval + nx - mx} "
302    kv["LHSq"] = f""
303    kv["LHSsubq"] = f""
304    kv["LHSvalq"] = f""
305    kv["RHS"] = f"{na}"
306    kv["RHSq"] = f""
307    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
308    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
309    return kv
310
311
312def add_times_dict():
313    # xsol = x; xval is test val
314    # mx * (x + nx) = na
315    nx = random.randint(1, 10)
316    mx = random.randint(2, 10)
317    xsol = random.randint(1, 10)
318    na = mx * (xsol + nx)
319    #
320    kv = dict()
321    if random.randint(1, 10) > 6:
322        xval = xsol + get_offset()
323        kv["side_equality"] = r"\neq"
324        kv["is_a_sol"] = "is not "
325    else:
326        xval = xsol
327        kv["side_equality"] = "="
328        kv["is_a_sol"] = "is "
329    #
330    kv["pro_value"] = f"x = {xval}"
331    kv["equation"] = f"{mx}(x + {nx}) = {na}"
332    kv["LHS"] = f"{mx}(x + {nx})"
333    kv["LHSsub"] = f"{mx} \\times({xval} + {nx})"
334    kv["LHSval"] = f"{mx * (xval + nx)} "
335    kv["LHSq"] = f""
336    kv["LHSsubq"] = f""
337    kv["LHSvalq"] = f""
338    kv["RHS"] = f"{na}"
339    kv["RHSq"] = f""
340    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
341    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
342    return kv
343
344
345def add_div_dict():
346    # xsol = x; xval is test val
347    # (x + nx)/mx = na
348    nx = random.randint(1, 10)
349    mx = random.randint(2, 10)
350    na = random.randint(1, 10)
351    xsol = (na * mx) - nx
352    #
353    kv = dict()
354    if random.randint(1, 10) > 6:
355        xval = xsol + (get_offset() * mx)
356        kv["side_equality"] = r"\neq"
357        kv["is_a_sol"] = "is not "
358    else:
359        xval = xsol
360        kv["side_equality"] = "="
361        kv["is_a_sol"] = "is "
362    #
363    kv["pro_value"] = f"x = {xval}"
364    kv["equation"] = f"\\frac{{x + {nx}}}{{{mx}}} = {na}"
365    kv["LHS"] = f"\\frac{{x + {nx}}}{{{mx}}}"
366    kv["LHSsub"] = f"\\frac{{{xval} + {nx}}}{{{mx}}}"
367    kv["LHSval"] = f"{(xval + nx) / mx}"
368
369    kv["LHSq"] = f""
370    kv["LHSsubq"] = f""
371    kv["LHSvalq"] = f""
372    kv["RHS"] = f"{na}"
373    kv["RHSq"] = f""
374    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
375    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
376    return kv
377
378
379def sub_add_dict():
380    # x - nx + mx = na
381    # xsol = x; xval is test val
382    nx = random.randint(1, 10)
383    mx = random.randint(1, 10)
384    na = random.randint(1, 10)
385    xsol = na + nx - mx
386    #
387    kv = dict()
388    if random.randint(1, 10) > 6:
389        xval = xsol + get_offset()
390        kv["side_equality"] = r"\neq"
391        kv["is_a_sol"] = "is not "
392    else:
393        xval = xsol
394        kv["side_equality"] = "="
395        kv["is_a_sol"] = "is "
396    #
397    kv["pro_value"] = f"x = {xval}"
398    kv["equation"] = f"x - {nx} + {mx} = {na}"
399    kv["LHS"] = f"x - {nx} + {mx}"
400    kv["LHSsub"] = f"{xval} - {nx} + {mx}"
401    kv["LHSval"] = f"{xval - nx + mx} "
402    kv["LHSq"] = f""
403    kv["LHSsubq"] = f""
404    kv["LHSvalq"] = f""
405    kv["RHS"] = f"{na}"
406    kv["RHSq"] = f""
407    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
408    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
409    return kv
410
411
412def sub_sub_dict():
413    # x - nx - mx = na
414    # xsol = x; xval is test val
415    nx = random.randint(1, 10)
416    mx = random.randint(1, 10)
417    na = random.randint(1, 10)
418    xsol = na + nx + mx
419    #
420    kv = dict()
421    if random.randint(1, 10) > 6:
422        xval = xsol + get_offset()
423        kv["side_equality"] = r"\neq"
424        kv["is_a_sol"] = "is not "
425    else:
426        xval = xsol
427        kv["side_equality"] = "="
428        kv["is_a_sol"] = "is "
429    #
430    kv["pro_value"] = f"x = {xval}"
431    kv["equation"] = f"x - {nx} - {mx} = {na}"
432    kv["LHS"] = f"x + {nx} - {mx}"
433    kv["LHSsub"] = f"{xval} - {nx} - {mx}"
434    kv["LHSval"] = f"{xval - nx - mx} "
435    kv["LHSq"] = f""
436    kv["LHSsubq"] = f""
437    kv["LHSvalq"] = f""
438    kv["RHS"] = f"{na}"
439    kv["RHSq"] = f""
440    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
441    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
442    return kv
443
444
445def sub_times_dict():
446    # xsol = x; xval is test val
447    # mx * (x - nx) = na
448    nx = random.randint(1, 10)
449    mx = random.randint(2, 10)
450    xsol = random.randint(1, 10)
451    na = mx * (xsol - nx)
452    #
453    kv = dict()
454    if random.randint(1, 10) > 6:
455        xval = xsol + get_offset()
456        kv["side_equality"] = r"\neq"
457        kv["is_a_sol"] = "is not "
458    else:
459        xval = xsol
460        kv["side_equality"] = "="
461        kv["is_a_sol"] = "is "
462    #
463    kv["pro_value"] = f"x = {xval}"
464    kv["equation"] = f"{mx}(x - {nx}) = {na}"
465    kv["LHS"] = f"{mx}(x - {nx})"
466    kv["LHSsub"] = f"{mx} \\times({xval} - {nx})"
467    kv["LHSval"] = f"{mx * (xval - nx)} "
468    kv["LHSq"] = f""
469    kv["LHSsubq"] = f""
470    kv["LHSvalq"] = f""
471    kv["RHS"] = f"{na}"
472    kv["RHSq"] = f""
473    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
474    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
475    return kv
476
477
478def sub_div_dict():
479    # xsol = x; xval is test val
480    # (x - nx)/mx = na
481    nx = random.randint(1, 10)
482    mx = random.randint(2, 10)
483    na = random.randint(1, 10)
484    xsol = (na * mx) + nx
485    #
486    kv = dict()
487    if random.randint(1, 10) > 6:
488        xval = xsol + (get_offset() * mx)
489        kv["side_equality"] = r"\neq"
490        kv["is_a_sol"] = "is not "
491    else:
492        xval = xsol
493        kv["side_equality"] = "="
494        kv["is_a_sol"] = "is "
495    #
496    kv["pro_value"] = f"x = {xval}"
497    kv["equation"] = f"\\frac{{x - {nx}}}{{{mx}}} = {na}"
498    kv["LHS"] = f"\\frac{{x - {nx}}}{{{mx}}}"
499    kv["LHSsub"] = f"\\frac{{{xval} - {nx}}}{{{mx}}}"
500    kv["LHSval"] = f"{(xval - nx) / mx}"
501
502    kv["LHSq"] = f""
503    kv["LHSsubq"] = f""
504    kv["LHSvalq"] = f""
505    kv["RHS"] = f"{na}"
506    kv["RHSq"] = f""
507    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
508    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
509    return kv
510
511
512def times_add_dict():
513    # xsol = x; xval is test val
514    # (x * nx) + mx = na
515    nx = random.randint(2, 10)
516    mx = random.randint(1, 10)
517    xsol = random.randint(1, 10)
518    na = (xsol * nx) + mx
519    #
520    kv = dict()
521    if random.randint(1, 10) > 6:
522        xval = xsol + get_offset()
523        kv["side_equality"] = r"\neq"
524        kv["is_a_sol"] = "is not "
525    else:
526        xval = xsol
527        kv["side_equality"] = "="
528        kv["is_a_sol"] = "is "
529    #
530    kv["pro_value"] = f"x = {xval}"
531    kv["equation"] = f"{nx}x + {mx} = {na}"
532    kv["LHS"] = f"{nx}x + {mx}"
533    kv["LHSsub"] = f"{nx} \\times{xval} + {mx}"
534    kv["LHSval"] = f"{(xval * nx) + mx } "
535    kv["LHSq"] = f""
536    kv["LHSsubq"] = f""
537    kv["LHSvalq"] = f""
538    kv["RHS"] = f"{na}"
539    kv["RHSq"] = f""
540    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
541    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
542    return kv
543
544
545def times_sub_dict():
546    # xsol = x; xval is test val
547    # (x * nx) - mx = na
548    nx = random.randint(2, 10)
549    mx = random.randint(1, 10)
550    xsol = random.randint(1, 10)
551    na = (xsol * nx) - mx
552    #
553    kv = dict()
554    if random.randint(1, 10) > 6:
555        xval = xsol + get_offset()
556        kv["side_equality"] = r"\neq"
557        kv["is_a_sol"] = "is not "
558    else:
559        xval = xsol
560        kv["side_equality"] = "="
561        kv["is_a_sol"] = "is "
562    #
563    kv["pro_value"] = f"x = {xval}"
564    kv["equation"] = f"{nx}x - {mx} = {na}"
565    kv["LHS"] = f"{nx}x - {mx}"
566    kv["LHSsub"] = f"{nx} \\times{xval} - {mx}"
567    kv["LHSval"] = f"{(xval * nx) - mx } "
568    kv["LHSq"] = f""
569    kv["LHSsubq"] = f""
570    kv["LHSvalq"] = f""
571    kv["RHS"] = f"{na}"
572    kv["RHSq"] = f""
573    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
574    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
575    return kv
576
577
578def times_times_dict():
579    # xsol = x; xval is test val
580    # x * nx * mx = na
581    nx = random.randint(2, 10)
582    mx = random.randint(2, 10)
583    xsol = random.randint(1, 10)
584    na = xsol * nx * mx
585    #
586    kv = dict()
587    if random.randint(1, 10) > 6:
588        xval = xsol + get_offset()
589        kv["side_equality"] = r"\neq"
590        kv["is_a_sol"] = "is not "
591    else:
592        xval = xsol
593        kv["side_equality"] = "="
594        kv["is_a_sol"] = "is "
595    #
596    kv["pro_value"] = f"x = {xval}"
597    kv["equation"] = f"{nx}x \\times {mx} = {na}"
598    kv["LHS"] = f"{nx}x \\times {mx}"
599    kv["LHSsub"] = f"{nx} \\times{xval} \\times {mx}"
600    kv["LHSval"] = f"{xval * nx * mx } "
601    kv["LHSq"] = f""
602    kv["LHSsubq"] = f""
603    kv["LHSvalq"] = f""
604    kv["RHS"] = f"{na}"
605    kv["RHSq"] = f""
606    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
607    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
608    return kv
609
610
611def times_div_dict():
612    # xsol = x; xval is test val
613    # (x * nx)/mx = na
614    nx = random.randint(2, 10)
615    xsol = random.randint(2, 10)
616    mx_candidates = [i for i in range(2, 11) if (xsol * nx) % i == 0]
617    mx = random.choice(mx_candidates)
618    na = (xsol * nx) // mx
619    #
620    kv = dict()
621    if random.randint(1, 10) > 6:
622        xval = xsol + (get_offset() * mx)
623        kv["side_equality"] = r"\neq"
624        kv["is_a_sol"] = "is not "
625    else:
626        xval = xsol
627        kv["side_equality"] = "="
628        kv["is_a_sol"] = "is "
629    #
630    kv["pro_value"] = f"x = {xval}"
631    kv["equation"] = f"\\frac{{{nx}x}}{{{mx}}} = {na}"
632    kv["LHS"] = f"\\frac{{{nx}x}}{{{mx}}}"
633    kv["LHSsub"] = f"\\frac{{{nx} \\times{xval}}}{{{mx}}}"
634    kv["LHSval"] = f"{(xval * nx) / mx}"
635
636    kv["LHSq"] = f""
637    kv["LHSsubq"] = f""
638    kv["LHSvalq"] = f""
639    kv["RHS"] = f"{na}"
640    kv["RHSq"] = f""
641    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
642    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
643    return kv
644
645
646def div_add_dict():
647    # xsol = x; xval is test val
648    # x/nx + mx = na
649    nx = random.randint(2, 10)
650    mx = random.randint(1, 10)
651    na = random.randint(1, 10)
652    xsol = (na - mx) * nx
653    #
654    kv = dict()
655    if random.randint(1, 10) > 6:
656        xval = xsol + (get_offset() * nx)
657        kv["side_equality"] = r"\neq"
658        kv["is_a_sol"] = "is not "
659    else:
660        xval = xsol
661        kv["side_equality"] = "="
662        kv["is_a_sol"] = "is "
663    #
664    kv["pro_value"] = f"x = {xval}"
665    kv["equation"] = f"\\frac{{x}}{{{nx}}} + {mx} = {na}"
666    kv["LHS"] = f"\\frac{{x}}{{{nx}}} + {mx}"
667    kv["LHSsub"] = f"\\frac{{{xval}}}{{{nx}}} + {mx}"
668    kv["LHSval"] = f"{(xval // nx) + mx}"
669
670    kv["LHSq"] = f""
671    kv["LHSsubq"] = f""
672    kv["LHSvalq"] = f""
673    kv["RHS"] = f"{na}"
674    kv["RHSq"] = f""
675    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
676    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
677    return kv
678
679
680def div_sub_dict():
681    # xsol = x; xval is test val
682    # x/nx - mx = na
683    nx = random.randint(2, 10)
684    mx = random.randint(1, 10)
685    na = random.randint(1, 10)
686    xsol = (na + mx) * nx
687    #
688    kv = dict()
689    if random.randint(1, 10) > 6:
690        xval = xsol + (get_offset() * nx)
691        kv["side_equality"] = r"\neq"
692        kv["is_a_sol"] = "is not "
693    else:
694        xval = xsol
695        kv["side_equality"] = "="
696        kv["is_a_sol"] = "is "
697    #
698    kv["pro_value"] = f"x = {xval}"
699    kv["equation"] = f"\\frac{{x}}{{{nx}}} - {mx} = {na}"
700    kv["LHS"] = f"\\frac{{x}}{{{nx}}} - {mx}"
701    kv["LHSsub"] = f"\\frac{{{xval}}}{{{nx}}} - {mx}"
702    kv["LHSval"] = f"{(xval // nx) - mx}"
703
704    kv["LHSq"] = f""
705    kv["LHSsubq"] = f""
706    kv["LHSvalq"] = f""
707    kv["RHS"] = f"{na}"
708    kv["RHSq"] = f""
709    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
710    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
711    return kv
712
713
714def div_times_dict():
715    # xsol = x; xval is test val
716    # (x / nx) * mx = na
717    mx = random.randint(2, 10)
718    xsol = random.randint(2, 10)
719    nx_candidates = [i for i in range(2, 11) if (xsol * mx) % i == 0]
720    nx = random.choice(nx_candidates)
721    na = (xsol * mx) // nx
722    #
723    kv = dict()
724    if random.randint(1, 10) > 6:
725        xval = xsol + (get_offset() * nx)
726        kv["side_equality"] = r"\neq"
727        kv["is_a_sol"] = "is not "
728    else:
729        xval = xsol
730        kv["side_equality"] = "="
731        kv["is_a_sol"] = "is "
732    #
733    kv["pro_value"] = f"x = {xval}"
734    kv["equation"] = f"\\frac{{x}}{{{nx}}} \\times {mx} = {na}"
735    kv["LHS"] = f"\\frac{{x}}{{{nx}}} \\times {mx}"
736    kv["LHSsub"] = f"\\frac{{{xval}}}{{{nx}}} \\times {mx}"
737    kv["LHSval"] = f"{(xval * mx) // nx}"
738
739    kv["LHSq"] = f""
740    kv["LHSsubq"] = f""
741    kv["LHSvalq"] = f""
742    kv["RHS"] = f"{na}"
743    kv["RHSq"] = f""
744    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
745    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
746    return kv
747
748
749def div_div_dict():
750    # bc = (nx / na) / nb
751    # escape {} in f strings by doubling them up {{}}
752    # xsol = x; xval is test val
753    # (x / nx) / mx = na
754    mx = random.randint(2, 7)
755    nx = random.randint(2, 7)
756    na = random.randint(2, 7)
757    xsol = na * mx * nx
758    #
759    kv = dict()
760    if random.randint(1, 10) > 6:
761        xval = xsol + (get_offset() * nx)
762        kv["side_equality"] = r"\neq"
763        kv["is_a_sol"] = "is not "
764    else:
765        xval = xsol
766        kv["side_equality"] = "="
767        kv["is_a_sol"] = "is "
768    #
769    kv["pro_value"] = f"x = {xval}"
770    kv["equation"] = f"\\frac{{x}}{{{nx}}} \\times \\frac{{1}}{{{mx}}} = {na}"
771    kv["LHS"] = f"\\frac{{x}}{{{nx}}} \\times \\frac{{1}}{{{mx}}}"
772    kv["LHSsub"] = f"\\frac{{{xval}}}{{{nx}}} \\times \\frac{{1}}{{{mx}}}"
773    kv["LHSval"] = f"{xval // (mx * nx)}"
774
775    kv["LHSq"] = f""
776    kv["LHSsubq"] = f""
777    kv["LHSvalq"] = f""
778    kv["RHS"] = f"{na}"
779    kv["RHSq"] = f""
780    kv["side_equalityq"] = r"\dotuline{\hspace{5mm}}"
781    kv["is_a_solq"] = r"\dotuline{\hspace{12mm}}"
782    return kv

2.3. Check solution diagram: LaTeX

1% inv op template
2\documentclass[12pt, varwidth, border=5mm]{standalone}
3\usepackage{amsmath}
4\usepackage{amssymb}  % For \therefore symbol
5\usepackage[normalem]{ulem}  % Prevents \emph from underlining text
6
7\begin{document}
8    <<diagram>>
9\end{document}
 1\noindent \textbf{Determine whether \(<<pro_value>>\) is a solution to the equation \(<<equation>>\):}
 2\vspace{4pt}  % Ensure spacing between problem statement and solution
 3
 4\noindent
 5\renewcommand{\arraystretch}{1.3} % Adjust line spacing in the aligned environment
 6\begin{tabular}{@{}p{0.45\linewidth}@{}p{0.45\linewidth}@{}}
 7    \(\begin{aligned}
 8        \text{LHS} &= <<LHS>> \\
 9                   &= <<LHSsub>> \\
10                   &= <<LHSval>>
11    \end{aligned}\) &
12    \(\begin{aligned}
13        \text{RHS} &= <<RHS>>\\
14                   & \\
15                   &
16    \end{aligned}\)
17\end{tabular}
18\renewcommand{\arraystretch}{1.0} % Adjust line spacing in the aligned environment
19\vspace{2pt}  % Optional spacing
20
21\noindent \(\therefore\) Since \(\text{LHS} <<side_equality>> \text{RHS}\), \(<<pro_value>>\) <<is_a_sol>> a solution to the equation.