Skip to content

a set of python3 scripts that generate math worksheets with answers.

License

Notifications You must be signed in to change notification settings

jacadzaca/zadanko

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

About

This repository contains code for 'zadanko' - a set of python3 scripts that generate math worksheets with answers.

Requirements

Installation

First ensure you have pdflatex and a document viewer

apt install texlive-latex-base texlive-fonts-recommended zathura # debian et al.
pacman -Syy texlive-most zathura # arch

Install zadanko:

git clone https://github.com/jacadzaca/zadanko && cd zadanko && python3 -m pip install -r requirements.txt .

Examples

#!/usr/bin/env python3
import random
import collections

import sympy
from jinja2 import Environment, PackageLoader

from zadanko import quadratics

Task = collections.namedtuple('Task', ['instruction', 'problems', 'awnsers'])

ENV = Environment(
    loader=PackageLoader('zadanko'),
    trim_blocks=True,
    lstrip_blocks=True)

def generate_quadratics_task():
    # generate diffrent kinds of quadratic equations
    zero_solutions_quadratics = [quadratics.generate_quadratic_zero_solutions() for _ in range(10)]
    one_solution_quadratics = [quadratics.generate_quadratic_one_solution() for _ in range(10)]
    two_solutions_quadratics = [quadratics.generate_quadratic_two_solutions() for _ in range(6)]
    # sort them according to 'difficulty' - the greater the sum of quadratic's coefficients, the more difficult it is
    zero_solutions_quadratics.sort(key=quadratics.quadratic_difficulty_comperator)
    one_solution_quadratics.sort(key=quadratics.quadratic_difficulty_comperator)
    two_solutions_quadratics.sort(key=quadratics.quadratic_difficulty_comperator)

    # arrange the problems in random order, but try to keep the problem's difficulty incremental
    problems = []
    problem_lists = [zero_solutions_quadratics, one_solution_quadratics, two_solutions_quadratics]
    for _ in range(sum(map(len, problem_lists))):
        choice = random.choice(problem_lists)
        problems.append(choice.pop())
        if not choice:
            problem_lists.remove(choice)

    # generate the awnsers with sympy https://docs.sympy.org/latest/index.html
    awnsers = (sympy.printing.latex((sympy.solvers.solveset(quadratic, domain=sympy.S.Reals))) for quadratic in problems)
    # generate LaTeX code
    problems = map(sympy.printing.latex, problems)
    return Task('Find the roots of function $f$, given by expression:', problems, awnsers)

if __name__ == '__main__':
    #output latex code
    latex = ENV \
            .get_template('problem_sheet.jinja.tex') \
            .render(tasks=[generate_quadratics_task()])
    print(latex)
#!/usr/bin/env python3
import itertools
import collections

import sympy
from jinja2 import Environment, PackageLoader

from zadanko import elementary_functions

Task = collections.namedtuple('Task', ['instruction', 'problems', 'awnsers'])

ENV = Environment(
    loader=PackageLoader('zadanko'),
    trim_blocks=True,
    lstrip_blocks=True)

def take(iterable, n):
    "Return first n items of the iterable as a list"
    return list(itertools.islice(iterable, n))

def generate_differentiation_task():
    # generate 10 elementary functions that are made out of 2 composite functions and append them to the problem list
    differentiation_problems = take(elementary_functions.elementary_function_generator(2), 10)
    # generate 10 elementary functions that are at most made out of 2 composite functions and then append the multiplication of them to the problem list
    for function, function1 in zip(take(elementary_functions.elementary_function_generator(2), 10), take(elementary_functions.elementary_function_generator(2), 10)):
        differentiation_problems.append(function * function1)
    # generate 6 elementary functions that are madeout of 3 composite functions and append them to the problem list
    differentiation_problems += take(elementary_functions.elementary_function_generator(3), 6)
    # sort them by how 'complicated' they are - the more 'composite', the later it's in the list
    differentiation_problems.sort(key=sympy.count_ops)
    # differentiate and generate LaTeX code
    awnsers = (sympy.printing.latex(function.diff()) for function in differentiation_problems)
    # generate LaTeX code for problem statments
    differentiation_problems = map(sympy.printing.latex, differentiation_problems)
    return Task('Find the derivative of function $f$, given by expression:', differentiation_problems, awnsers)

if __name__ == '__main__':
    # output the LaTeX code
    latex = ENV \
            .get_template('problem_sheet.jinja.tex') \
            .render(tasks=[generate_differentiation_task()])
    print(latex)
#!/usr/bin/env python3
import collections
import itertools

import sympy
from jinja2 import Environment, PackageLoader

from zadanko import elementary_functions

Task = collections.namedtuple('Task', ['instruction', 'problems', 'awnsers'])

ENV = Environment(
    loader=PackageLoader('zadanko'),
    trim_blocks=True,
    lstrip_blocks=True)

# https://docs.python.org/3/library/itertools.html#itertools-recipes
def take(iterable, n):
    "Return first n items of the iterable as a list"
    return list(itertools.islice(iterable, n))

def generate_integration_task():
    # generate awnsers first - it's easier to ensure the problems will be integrable that way
    awnsers = take(filter(lambda expr: expr.diff() != 1, elementary_functions.elementary_function_generator(2)), 16)
    random_functions = itertools.cycle(elementary_functions.elementary_function_generator(1))
    awnsers += ((left_func * right_func) for left_func, right_func in zip(take(random_functions, 10), take(random_functions, 10)))
    awnsers.sort(key=sympy.count_ops)
    # generate problems
    problems = (sympy.printing.latex(function.diff()) for function in awnsers)
    awnsers = map(sympy.printing.latex, awnsers)

    return Task('Integrate function $f$, given by expression:', problems, awnsers)

if __name__ == '__main__':
    latex = ENV \
            .get_template('problem_sheet.jinja.tex') \
            .render(tasks=[generate_integration_task()])
    print(latex)
#!/usr/bin/env python3
# keep in mind this depends on the previous scripts

from jinja2 import Environment, PackageLoader

from generate_quadratics_worksheet import generate_quadratics_task
from generate_differentiation_worksheet import generate_differentiation_task
from generate_integration_worksheet import generate_integration_task

ENV = Environment(
    loader=PackageLoader('zadanko', 'templates'),
    trim_blocks=True,
    lstrip_blocks=True)

if __name__ == '__main__':
    latex = ENV \
            .get_template('problem_sheet.jinja.tex') \
            .render(tasks=[generate_quadratics_task(), generate_differentiation_task(), generate_integration_task()])
    print(latex)

To compile use:

chmod +x example.py && ./example.py | pdflatex --jobname worksheet --output-directory /tmp && zathura /tmp/worksheet.pdf

See examples for more

Legal Note

The code is licensed under GPL 3.0.