# Gezmat - generator of sets of mathematical and other problems

Version 2018-02-24
Automatic production of sets of problems, every set in many versions with different numerical values, pictures, choice of questions etc.
For each version automatic production of files with:
• only problems (PDF, LaTeX)
• problems and answers (PDF, LaTeX)
• problems, hints and answers (PDF, LaTeX, txt)
• Program: GNU GPL
• Problems : CC BY-SA
More information  can be found on this page or in the LICENCE directory of the package.

Examples of sets (1 version, PDF: P - problems, PA - problems with answers, PHA - problems with hints and answers, 4 versions as PDF, TEX, TXT in each ZIP archive):
Specify the maximal number of decimal places for basic level problems; id of these problems ends with -dpc.
At the moment there are only 35 problems prepared to demonstrate the concept. They are mainly on the primary school level. More problems, with graphs and more advanced pictures, are already prepared in  Polish  and will be translated into English.
All problems (1 version):  P  PA  PHA  ZIP
Easily choose the problems and prepare your own sets by simple edition of the configuration text file.

Corrections of the code after the entire generation moved to the working directory (all_problems_* was not copied to def/).

Quick start
$tar xf Gezmat-[...].tgz$ cd Gezmat-[...]/
Install  necessary packages  on the systems with APT (Ubuntu, Mint, Debian):
$sudo ./install-pkgs-for-gezmat.bash Enter the password, later confirm (Enter or Y).$ ./gezmat.bash def/en-simple_test.gzm
In the directory
Outputs/en-simple_test-[...]/
will apprear directiories pdf, tex, txt with sets of problems.
Required software:
• terminal/console (this is not a "window" program)
• bash shell
• g++-6 compiler with standard libraries
• LaTeX/TeX: latex, dvips (texlive packages); ghostscript with ps2pdf. Or: pdflatex
• Asymptote (vector graphics)
The package was tested on Linux.  How to easily install these packages.

Gezmat also runs in Windows Subsystem for Linux on Windows 10 (install guide).

Program works on Mac OS systems, too.

We would be grateful for information if you succeed to run Gezmat on other system.
Example of a production of a set defined in the file
def/en-simple_test.gzm
Produced are 3 versions. For each version files PDF and LaTeX with the extension:
• _ha include problems, hints, answers, information about authors, date of last modification, and identifiers (ids) of problems
• _a include problems with answers
Other PDF and LaTeX files contain only problems, and the TXT file problems with hints and answers. The commands are invoked in the console, at the root directory of the package, which is created after extracting the tgz archive (eg. Gezmat-2016-07-14/). A folder Outputs/en-simple_test... is created to which are transferred the generated files with extensions pdf, tex, txt; other files (such as dvi, ps) can be found in the working directory Work_files/other (this directory is overwritten each run of the program).
$./gezmat.bash def/en-simple_test.gzm 3$ cd Outputs/en-simple_test-2016-07-14-22/
$ls -1 * en-simple_test_v01_a.pdf en-simple_test_v01_a.tex en-simple_test_v01_ha.pdf en-simple_test_v01_ha.tex en-simple_test_v01.pdf en-simple_test_v01.tex en-simple_test_v01.txt en-simple_test_v02_a.pdf ... en-simple_test_v02_ha.pdf ... en-simple_test_v02.pdf ... en-simple_test_v02.txt ... en-simple_test_v03_ha.pdf ... The file def/all_problems_en.gzm contains ids of all problems in English, do not edit this file. Instead, change its name, for example to en-my-test.gzm, change the description and leave only chosen problems. Then produce your sets in the same way as with the file en-simple_test.gzm. A configuration file does not have to be in the directory def/. You can store your configuration files in the directory priv-def/, for example. A configuration file must have .gzm extension and its first 7 lines have to contain in the following order: 1. Title (any string) 2. Language code, only pl or en for now 3. Decimal mark, dot or comma for example 4. Maximal number of decimal places in case of basic level problems (0 or 1, or 2 for example) 5. Place and date (any string) 6. Author of the configuration file (any string) 7. Description (any string) In "any strings" LaTeX commands can be used. In the following non-emty lines - that can be separated with empty ones - as the first word must be present: • a word gzm that introduces a Gezmat command • or an identifier (id) of the problem All identifiers of problems can be found in the file def/all_problems_en.gzm or in the files in the directory Outputs/all_problems_en... with _ha in the name. Relevant is only an identifier, the title can be kept for convenience. A sample file defining a set: Test en . 1 Warszawa, 2016-07-31 \emph{ Prepared by \textbf{ J.F.} } % LaTeX Good luck! en-numbers-0000500 "Number of pages" en-numbers-0001000 "Plums" gzm comment Indentation is OK en-numbers-0002000 "Apples" en-rectangles-0001000 "Sides of rectangles" en-speed-distance-time-0004000-dpc "Cycling speed" For people who can program in any language the possibility to add new problems (C++, LaTeX, Asymptote). Each problem is written as a lambda expression. For authors of the problems - fragments of the files in the directory src/: // Random integer in // [min, max] for n=0 // [min*10^n, max*10^n] for n>0 // r(4,6) returns number in [4, 6] // r(4,6,2) returns number in [400, 600] int r(int min, int max, int n=0) // String corresponding to real/10^n // (move decimal mark n places to the left) // s(102,2) --> "1.02" // s(102) --> "102" // s(30,3) --> "0.03" string s(int number, int n=0) // Plums - simplified version addProblem ("en-numbers-0001000", // ID (string) "Plums", // Title (string) "Piotr Nieżurawski", // Authors (string) "2016-07-11", // Date of the last update (string) 1, // Difficulty (int) []{ // Lambda expression (returns vector<string>) string text = "John had "; int n = 3*r(5,12); text += s(n); text += " plums. Then he ate one-third of them. How many plums has John now?"; vector<string> pV; pV.push_back(text); // Hint text = "How much is "; text += s(n) + ":3? Answer: " + s(n/3) + "."; pV.push_back(text); // Answer text = "John has "; int answer = 2*n/3; text += s(answer); text += " plums."; pV.push_back(text); return pV; } // End of lambda expression ); // End of addProblem Authors of problems are indicated in the file all_problems_en_ha.pdf Authors of problems in chronological order: Piotr Nieżurawski Piotr.Niezurawski@pionie.com Code, coordination, web page: Piotr Nieżurawski Piotr.Niezurawski@pionie.com Other my projects: pionie.com Want to help, report a bug, ask? Visit discussion group Gezmat EN or send a mail to the coordinator Piotr.Niezurawski@pionie.com . Plans: problems at the level of primary education, fractions; physics problems for high school, problems with generated tables, graphs (motion, dynamics, thermodynamic processes). GNU GPL Program Gezmat is available under the terms of the open licence GNU General Public License as published by the Free Software Foundation version 3 https://www.gnu.org/licenses/gpl.txt Descriptions of problems produced by running the Gezmat code or files with extension .gzm defining the sets of problems are available under the terms of the open licence CC BY-SA 4.0, Creative Commons - Attribution - ShareAlike 4.0 International Public License http://creativecommons.org/licenses/by-sa/4.0/ If you modify the sets of problems and want to publish them, include a clearly visible reference to the project's web page gezmat.com where authors of the code and problems are listed. Detailed reference to an author per each problem is not necessary. Such derivative work, according to the licence, should contain as well the licence information at least in the form of clearly visible CC BY-SA 4.0 For more information about licence of Gezmat see the files in the directory LICENCE in the package. If you modify files with the code of Gezmat, and you want to redistribute it in any way, add in the modified file your name and e-mail address in the appriopriate 'Authors' line, add the date of modification. Include only what you created or what is in public domain. Sent to the coordinator or publicly accessible modifications and submissions indicate the contributors' assent for inclusion of that software in the canonical version under the project's license. Please, inform the coordinator about your contributions and modifications. To install necessary packages on the systems with APT (Ubuntu, Mint, Debian) run:$ sudo ./install-pkgs-for-gezmat.bash
Enter the password, later confirm (Enter or Y).
The following packages are installed:
• g++-6 with standard libraries (the Ubuntu test repository is added)
• selected TeXLive packages, including texlive-lang-english
• Ghostscript
• Asymptote
• sed

If you prefer pdflatex instead of latex:
$./gezmat.bash def/en-sets.gzm 1 pdflatex Remember to indicate the number of versions (in this case it cannot be empty). More versions:$ ./gezmat.bash def/en-sets.gzm 4 pdflatex

Commands that can be placed starting at the 8 line in the configuration file (def/*.gzm)
Commands used only once per a set, affect the whole set:
gzm for-all-vspace 2cm
Insert vertical space after each problem (only P).  ZIP
gzm only-number
Only the number of the problem, without a line break (only P).  ZIP
gzm only-number-and-title
The numer and title of the problem, without "Problem -" (only P).  ZIP
Insert a text in the header on the left.  ZIP
gzm search-id speed
Choose only problems (in the chosen language) whose ids include regular expression.  more   ZIP
gzm search-description John
Choose only problems (in the chosen language) whose descriptions include regular expression.  more   ZIP
gzm search-author Nieżurawski
Choose only problems (in the chosen language) whose list of authors includes regular expression.  more   ZIP
gzm shuffle
Shuffle randomly problems.  ZIP
Generate much more versions of the set and select those with the best layout of text and pictures.
To shuffle only a group of problems use from-group-choose command and choose as many problems as there are in the group.
gzm all-problems-config
Prepare a set with all problems in the chosen language and the file def/all_problems_*.gzm.  ZIP
Define page paramters. Default: a4paper, verbose, tmargin=2cm, bmargin=2cm, lmargin=2cm, rmargin=2cm, headheight=0.7cm, headsep=2mm.  ZIP
gzm points 1.45 2
Write a number of points at each problem. The first number (optional, real) is the factor by which diff, the difficulty of the problem, will be multiplied: the number of points for a problem = integer part of [factor]*[diff of a problem]. The second number (optional, integer) is the minimum number of points per problem (each problem will have at least this number of points). If only gzm points is used, without numbers, the number of points for the problem is equal to its diff value.

The diff values ​​are listed in the PHA file (*_ha.pdf). For convenience, the total number of points for a set is printed in the terminal after the generation of the set in which command points is used. Defining a set you can modify the assigned diff value with the command gzm difficulty [integer]. Combined use of these two commands allows you to obtain a desired total number of points for a set with a guarantee that the given problem will have the same number of points in each set version.
ZIP
Commands that can be placed in the configuration file after a line with the problem identifier:
gzm vspace 4cm
Insert vertical space after the problem (only P).  ZIP
gzm insert ~\\ Check \textit{the result}!
Insert a text after the problem.  ZIP
gzm insert-before ~\\ \textbf{Breathe!} \\[-1em]
Insert a text before the problem.  ZIP
gzm grid 0.5cm 17cm 3cm
Insert a grid after the problem; parameters: step, width, height; no space between units (here cm) and numbers (only P).   ZIP
Width of the grid = width of the text:
gzm grid 0.5cm \textwidth 5cm
Grid at the end of the page and on the next page.
en-numbers-0000500 "Number of pages"

gzm insert \\ \begin{tikzpicture} \draw[step=0.5cm,gray!60,thick] (0, 0) grid (\textwidth, 9.5cm); \end{tikzpicture}

gzm grid 0.5cm \textwidth \textheight
Warning: everything added by "insert" appears as well in files with hints and answers (PA, PHA).
gzm difficulty 2
Modify the assigned to the problem diff (difficulty) value. Parameter: new diff value. Refer to the command gzm points  ZIP
Commands that apply to a group of problem identifiers:
gzm from-group-choose 2
gzm end-group
Choose randomly and in random order the specified number of identifiers from the group of identifiers (here 2 from 3).   ZIP
Generate much more versions of the set and select those with the best layout of text and pictures.

Special commands:
gzm comment Anything here
Comment.

Examples of searches of the problems containing a regular expression. The following commands can be placed starting from the 8 line in the configuration file (def/*.gzm). The regular expression must start after an interval of exactly one space after the command. Remove unnecessary spaces after the end of the phrase.

If you use two or three of commands search-author, search-description, search-id, the problems fulfilling all conditions are selected.  ZIP
gzm search-id time
Choose problems whose id includes "time".
gzm search-id apple|plum
Choose problems whose id includes "apple" or "plum".
gzm search-id (?!.*set.*)(^.*\$)
Choose problems whose id does not include "set".
gzm search-description [Aa]pple
Choose problems whose description includes "Apple" or "apple".
gzm search-description [Aa]pple|[Pp]lum
Choose problems whose description includes "Apple" or "apple" or "Plum" or "plum".
gzm search-description (?!.*John.*)(^.*Mark.*)
Choose problems whose description does not include "John" and includes "Mark".
gzm search-description (?!.*ectangle.*)(^.*)
Choose problems whose description does not include "ectangle".
gzm search-description (?!.*area.*)(^.*length.*)
Choose problems whose description does not include "area" and includes "length".
gzm search-description (?=.*[Pp]eeble)(?=.*[Ss]ee)
Choose problems whose description includes at the same time, in any order ["peeble" or "Peeble"] and ["see" or "See"]
Ids directly indicated in the configuration file are ignored.
Ids of chosen problems - and description of the regular expression - are stored in the file with ".rgx" extension in the subdirectory in Outputs. You can use this list of identifiers to define your set of problems.
In Gezmat the regular expressions supported by function regex_search from library regex (C++) are used, according to  the ECMAScript syntax , in case-sensitive mode.

Hints for authors of problems - easy start
In the directory src/, from the file
en-createProblemGeneratorMap-problems-include.cxx
copy one problem to the existing file
your-problems-include.cxx
In this file edit the problem. In the main Gezmat directory:
./gezmat.bash def/en-prepare-all-problems-config.gzm
And find your problem in produced files.
You can also create in the directory priv-def a file similar to the file def/en-simple_test_search-author.gzm to produce a set only with all your problems. That is:
cp def/en-simple_test_search-author.gzm priv-def/en-Your-Name-all_problems.gzm
Change "Nieżurawski" to your name. Then:
./gezmat.bash priv-def/en-Your-Name-all_problems.gzm

Hints for authors of problems - descriptions of functions

r(number,...)
// Random integer in:
// [min, max] for n=0
// [min*10^n, max*10^n] for n>0
// r(4,6) returns number in [4, 6]
// r(4,6,2) returns number in [400, 600]
int r(int min, int max, int n=0)
r(vector)
// Random integer from the input vector
// r({0, 3, 7}) returns one of numbers: 0, 3, 7.
int r(vector<int> vec)
s(...)
Only numbers as arguments:
// Return string corresponding to real/10^n (move period n places to the left)
// For example:
// s(102,2) --> "1.02"
// s(1020,3) --> "1.02"
// s(102) --> "102"
// s(3,2) --> "0.03"
string s(const int number, const int n=0)
A number and strings as arguments:
// Return string depending on the number:
// s(n,"apple","apples"): 1 apple, 2 apples...
// s(n,"times"): once, twice, 3 times...
string s(const int number, const string formA, const string formB = "", const string formC = "")
An example - see "Pebbles".

o(number, numberOfSignificantDigits)
// Function returns int rounded to specified number of significant digits
// Example: o(12332, 2) -> 12000
// Example: o(-12332, 2) -> -12000
// Example: o(1252, 2) -> 1300
// Example: o(-1252, 2) -> -1300
int o(const int number, const int numberOfSignificantDigits)
shuf(vector)
// Return shuffled vector
vector<T> shuf(vector<T> vec)
powInt(k, n)
// Function "power of k to n" returns k^n, only for n>=0.
int powInt(const int k, const int n)
p10(number)
// "power of 10" returns 10^n, for n>=0.
int p10(int n)
itod(number)
// Function returns double from int
// Example: itod(11) --> 11.0
double itod(const int i)
dtoi(number)
// Function returns int from double rounded by std::round()
// Example: dtoi(10.8) --> 11
int dtoi(const double d)
writeContainerElements(Iterator, Iterator)
// Function returns a string with sequence of integers or strings from a container separated by comma, e.g.: 1, 3, 5, 6
string writeContainerElements(Iterator it, const Iterator end, const string separator = ", ", const string flag = "")
in(x, leftBracket, a, rightBracket)
// Function returns LaTeX string of the form: x \in leftbracket a rightbracket, e.g. t \in { 10, 20, ..., 100 }
string in(string x, string leftBracket, string a, string rightBracket)
in(x, leftBracket, a, b, rightBracket)
// Function returns LaTeX string of the form: x \in leftbracket a, b rightbracket, e.g. t \in [ 10, 20 [
string in(string x, string leftBracket, string a, string b, string rightBracket)
In gezmat.cxx in namespace gezmatTools you can find definitions of other useful functions and objects:
numberToVectorOfStrings
numberLength
tableForOperation
triangleOfNumbers
tableWithTriangleOfNumbers
NumberSnakePicture

Hints for authors of problems - additional compiler options
To verify formally a new problem, run Gezmat with the option check:
./gezmat.bash def/en-sets.gzm 5 check
or
./gezmat.bash def/en-sets.gzm 5 pdflatex check
It is necessary to specify the number of versions. This option switches on additional compiler options:
-fsanitize=undefined
-fsanitize=integer-divide-by-zero
-fsanitize=float-divide-by-zero
-fsanitize=signed-integer-overflow
-fsanitize=float-cast-overflow
-fsanitize=bounds-strict
-fuse-ld=gold
Unfortunately, the compilation is then much longer.

Hints for authors of problems - shorter compilation time while testing a new problem
In the file
src/gezmat.cxx
in the function
void createProblemGeneratorMap ()
comment lines
#include "pl-createProblemGeneratorMap-problems-include.cxx"
#include "en-createProblemGeneratorMap-problems-include.cxx"
Then only problems in the file
src/your-problems-include.cxx
are compiled.