diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000..3252576 --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,21 @@ +name: Run tests + +on: [push, pull_request] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install -U pip + python -m pip install -r dev-requirements.txt + - name: Test + run: make test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c42af8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,138 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dbf1f17 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +test: + python -m pytest --verbose -s tests diff --git a/README.md b/README.md index 45ffcec..dfc7d41 100644 --- a/README.md +++ b/README.md @@ -30,21 +30,54 @@ problem, solution = mathgen.genById(0) | Id | Skill | Example problem | Example Solution | Function Name | |------|-----------------------------------|--------------------|-----------------------|--------------------------| -| 0 | Addition | 1+5= | 6 | addition | -| 1 | Subtraction | 9-4= | 5 | subtraction | -| 2 | Multiplication | 4*6= | 24 | multiplication | -| 3 | Division | 4/3= | 1.33333333 | division | -| 4 | Binary Complement 1s | 1010= | 0101 | binaryComplement1s | -| 5 | Modulo Division | 10%3= | 1 | moduloDivision | -| 6 | Square Root | sqrt(25)= | 5 | squareRootFunction | -| 7 | Power Rule Differentiation | 4x^3 | 12x^2 | powerRuleDifferentiation | -| 8 | Square | 4^2 | 16 | square | -| 9 | LCM (Least Common Multiple) | LCM of 14 and 9 = | 126 | lcm | -| 10 | GCD (Greatest Common Denominator) | GCD of 18 and 18 = | 18 | gcd | -| 11 | Basic Algebra | 9x + 7 = 10 | 1/3 | basicAlgebra | -| 12 | Logarithm | log3(3) | 1 | log | -| 13 | Easy Division | 270/15 = | 18 | intDivision | -| 14 | Decimal to Binary | Binary of a= | b | decimalToBinary | -| 15 | Binary to Decimal | Decimal of a= | b | binaryToDecimal | -| 16 | Fraction Division | (a/b)/(c/d)= | x/y | fractionDivision | -| 17 | Int 2x2 Matrix Multiplication | k * [[a,b],[c,d]]= | [[k*a,k*b],[k*c,k*d]] | intMatrix22Multiplication| +| 0 | Addition | 29+33= | 62 | addition | +| 1 | Subtraction | 62-7= | 55 | subtraction | +| 2 | Multiplication | 93*1= | 93 | multiplication | +| 3 | Division | 59/47= | 1.2553191489361701 | division | +| 4 | Binary Complement 1s | 001110000 | 110001111 | binaryComplement1s | +| 5 | Modulo Division | 89%34= | 21 | moduloDivision | +| 6 | Square Root | sqrt(16)= | 4 | squareRoot | +| 7 | Power Rule Differentiation | 4x^3 | 12x^2 | powerRuleDifferentiation | +| 8 | Square | 12^2= | 144 | square | +| 9 | LCM (Least Common Multiple) | LCM of 10 and 1 = | 10 | lcm | +| 10 | GCD (Greatest Common Denominator) | GCD of 12 and 5 = | 1 | gcd | +| 11 | Basic Algebra | 8x + 7 = 10 | 3/8 | basicAlgebra | +| 12 | Logarithm | log3(729) | 6 | log | +| 13 | Easy Division | 378/21 = | 18 | intDivision | +| 14 | Decimal to Binary | Binary of 4= | 100 | decimalToBinary | +| 15 | Binary to Decimal | 10011 | 19 | binaryToDecimal | +| 16 | Fraction Division | (1/2)/(4/3) | 3/8 | fractionDivision | +| 17 | Integer Multiplication with 2x2 Matrix | 2 * [[0, 7], [7, 7]] = | [[0,14],[14,14]] | intMatrix22Multiplication | +| 18 | Area of Triangle | Area of triangle with side lengths: 9 14 15 = | 61.644140029689765 | areaOfTriangle | +| 19 | Triangle exists check | Does triangle with sides 33, 6 and 43 exist? | No | doesTriangleExist | +| 20 | Midpoint of the two point | (-15,-10),(-5,2)= | (-10.0,-4.0) | midPointOfTwoPoint | +| 21 | Factoring Quadratic | x^2-17x+72 | (x-9)(x-8) | factoring | +| 22 | Third Angle of Triangle | Third angle of triangle with angles 4 and 31 = | 145 | thirdAngleOfTriangle | +| 23 | Solve a System of Equations in R^2 | 4x - 8y = 48, 3x - 8y = 40 | x = 8, y = -2 | systemOfEquations | +| 24 | Distance between 2 points | Find the distance between (-9, -20) and (18, -19) | sqrt(730) | distance2Point | +| 25 | Pythagorean Theorem | The hypotenuse of a right triangle given the other two lengths 18 and 13 = | 22.20 | pythagoreanTheorem | +| 26 | Linear Equations | -11x + -16y = -302 +1x + 20y = 250 | x = 10, y = 12 | linearEquations | +| 27 | Prime Factorisation | Find prime factors of 55 | [5, 11] | primeFactors | +| 28 | Fraction Multiplication | (4/9)*(8/10) | 16/45 | fractionMultiplication | +| 29 | Angle of a Regular Polygon | Find the angle of a regular polygon with 15 sides | 156.0 | angleRegularPolygon | +| 30 | Combinations of Objects | Number of combinations from 13 objects picked 1 at a time | 13 | combinations | +| 31 | Factorial | 2! = | 2 | factorial | +| 32 | Surface Area of Cube | Surface area of cube with side = 13m is | 1014 m^2 | surfaceAreaCubeGen | +| 33 | Surface Area of Cuboid | Surface area of cuboid with sides = 5m, 3m, 7m is | 142 m^2 | surfaceAreaCuboidGen | +| 34 | Surface Area of Cylinder | Surface area of cylinder with height = 15m and radius = 7m is | 967 m^2 | surfaceAreaCylinderGen | +| 35 | Volum of Cube | Volume of cube with side = 11m is | 1331 m^3 | volumeCubeGen | +| 36 | Volume of Cuboid | Volume of cuboid with sides = 6m, 1m, 10m is | 60 m^3 | volumeCuboidGen | +| 37 | Volume of cylinder | Volume of cylinder with height = 26m and radius = 15m is | 18378 m^3 | volumeCylinderGen | +| 38 | Surface Area of cone | Surface area of cone with height = 46m and radius = 14m is | 2730 m^2 | surfaceAreaConeGen | +| 39 | Volume of cone | Volume of cone with height = 7m and radius = 11m is | 886 m^3 | volumeConeGen | +| 40 | Common Factors | Common Factors of 91 and 51 = | [1] | commonFactors | +| 41 | Intersection of Two Lines | Find the point of intersection of the two lines: y = 6/4x + 5 and y = -7/2x + 3 | (-2/5, 22/5) | intersectionOfTwoLines | +| 42 | Permutations | Number of Permutations from 13 objects picked 4 at a time = | 17160 | permutations | +| 43 | Cross Product of 2 Vectors | [-14, 13, 20] X [-5, -18, 19] = | [607, 166, 317] | vectorCross | +| 44 | Compare Fractions | Which symbol represents the comparison between 8/3 and 6/7? | > | compareFractions | +| 45 | Simple Interest | Simple interest for a principle amount of 6128 dollars, 5% rate of interest and for a time period of 5 years is = | 1532.0 | simpleInterest | +| 46 | Multiplication of two matrices | Multiply [[-20, -14, -88, -62, 39, 94, 21, 75, 26], [89, -67, -80, -60, 32, -23, -79, 11, -69], [13, -75, -66, 3, 67, -79, -49, 6, 36], [-44, -84, 68, -27, -86, -95, -71, -77, -62], [45, 58, 89, 82, 30, -83, -23, 51, 95], [11, 46, 100, -15, 60, -34, 85, 50, -44], [93, -100, -62, 63, -73, -64, 90, -15, 23], [-8, 91, -22, 53, -42, 25, 32, -26, 31], [-60, 90, 75, -42, 19, 33, -30, 74, 13]] and [[-80, 54, -39, 37, -99], [31, -28, -31, 64, 73], [-21, -34, -28, -21, -76], [-94, 55, 66, 0, 17], [-28, 25, -65, -74, 100], [76, 74, -96, -98, -5], [-90, -70, -66, -71, -35], [65, 49, -100, 72, -23], [-95, -97, -31, -84, -86]] | [[15409, 6508, -21665, -10161, 5326], [9859, 17962, 3267, 12768, 3119], [-8761, 1272, 8611, 738, 3881], [4489, -5790, 29652, 11947, -5940], [-22167, -8208, -1142, 6747, -10714], [-4628, -5167, -15527, 1404, 243], [-29240, -2432, 11103, 615, -22487], [-5498, -5038, 1462, -100, 2495], [18214, -3238, -15548, 3691, 6061]] | matrixMultiplication | +| 47 | Cube Root | cuberoot of 711 upto 2 decimal places is: | 8.93 | CubeRoot | +| 48 | Power Rule Integration | 3x^1 | (3/1)x^2 + c | powerRuleIntegration | +| 49 | Fourth Angle of Quadrilateral | Fourth angle of quadrilateral with angles 94 , 101, 102 = | 63 | fourthAngleOfQuadrilateral | diff --git a/dev-requirements.txt b/dev-requirements.txt new file mode 100644 index 0000000..a965899 --- /dev/null +++ b/dev-requirements.txt @@ -0,0 +1,2 @@ +pytest +hypothesis \ No newline at end of file diff --git a/mathgenerator/__pycache__/__init__.cpython-37.pyc b/mathgenerator/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000..893336f Binary files /dev/null and b/mathgenerator/__pycache__/__init__.cpython-37.pyc differ diff --git a/mathgenerator/__pycache__/mathgen.cpython-37.pyc b/mathgenerator/__pycache__/mathgen.cpython-37.pyc new file mode 100644 index 0000000..418e0a5 Binary files /dev/null and b/mathgenerator/__pycache__/mathgen.cpython-37.pyc differ diff --git a/mathgenerator/mathgen.py b/mathgenerator/mathgen.py index fda0d0e..3a44119 100644 --- a/mathgenerator/mathgen.py +++ b/mathgenerator/mathgen.py @@ -1,5 +1,6 @@ import random import math +import fractions genList = [] @@ -419,6 +420,7 @@ def regularPolygonAngleFunc(minVal = 3,maxVal = 20): return problem, solution def combinationsFunc(maxlength=20): + def factorial(a): d=1 for i in range(a): @@ -427,6 +429,9 @@ def combinationsFunc(maxlength=20): return d a= random.randint(10,maxlength) b=random.randint(0,9) + + + solution= int(factorial(a)/(factorial(b)*factorial(a-b))) problem= "Number of combinations from {} objects picked {} at a time ".format(a,b) @@ -532,6 +537,183 @@ def commonFactorsFunc(maxVal=100): solution = arr return problem, solution +def intersectionOfTwoLinesFunc( + minM=-10, maxM=10, minB=-10, maxB=10, minDenominator=1, maxDenominator=6 +): + def generateEquationString(m, b): + """ + Generates an equation given the slope and intercept. + It handles cases where m is fractional. + It also ensures that we don't have weird signs such as y = mx + -b. + """ + if m[1] == 1: + m = m[0] + else: + m = f"{m[0]}/{m[1]}" + base = f"y = {m}x" + if b > 0: + return f"{base} + {b}" + elif b < 0: + return f"{base} - {b * -1}" + else: + return base + + def fractionToString(x): + """ + Converts the given fractions.Fraction into a string. + """ + if x.denominator == 1: + x = x.numerator + else: + x = f"{x.numerator}/{x.denominator}" + return x + + m1 = (random.randint(minM, maxM), random.randint(minDenominator, maxDenominator)) + m2 = (random.randint(minM, maxM), random.randint(minDenominator, maxDenominator)) + b1 = random.randint(minB, maxB) + b2 = random.randint(minB, maxB) + equation1 = generateEquationString(m1, b1) + equation2 = generateEquationString(m2, b2) + problem = "Find the point of intersection of the two lines: " + problem += f"{equation1} and {equation2}" + m1 = fractions.Fraction(*m1) + m2 = fractions.Fraction(*m2) + # if m1 == m2 then the slopes are equal + # This can happen if both line are the same + # Or if they are parallel + # In either case there is no intersection + if m1 == m2: + solution = "No Solution" + else: + intersection_x = (b1 - b2) / (m2 - m1) + intersection_y = ((m2 * b1) - (m1 * b2)) / (m2 - m1) + solution = f"({fractionToString(intersection_x)}, {fractionToString(intersection_y)})" + return problem, solution + +def permutationFunc(maxlength=20): + a = random.randint(10,maxlength) + b = random.randint(0,9) + solution= int(math.factorial(a)/(math.factorial(a-b))) + problem= "Number of Permutations from {} objects picked {} at a time = ".format(a,b) + return problem, solution + +def vectorCrossFunc(minVal=-20, maxVal=20): + a = [random.randint(minVal, maxVal) for i in range(3)] + b = [random.randint(minVal, maxVal) for i in range(3)] + c = [a[1]*b[2] - a[2]*b[1], + a[2]*b[0] - a[0]*b[2], + a[0]*b[1] - a[1]*b[0]] + return str(a) + " X " + str(b) + " = ", str(c) + +def compareFractionsFunc(maxVal=10): + a = random.randint(1, maxVal) + b = random.randint(1, maxVal) + c = random.randint(1, maxVal) + d = random.randint(1, maxVal) + + while (a == b): + b = random.randint(1, maxVal) + while (c == d): + d = random.randint(1, maxVal) + + first=a/b + second=c/d + + if(first>second): + solution=">" + elif(first 0: + problem += " + " + solution += " + " + coefficient = random.randint(1, maxCoef) + exponent = random.randint(1, maxExp) + problem += str(coefficient) + "x^" + str(exponent) + solution += "("+str(coefficient) +"/"+str(exponent) +")x^" + str(exponent +1) + solution = solution + " + c" + return problem, solution + + +def fourthAngleOfQuadriFunc(maxAngle = 180): + angle1 = random.randint(1, maxAngle) + angle2 = random.randint(1, 240-angle1) + angle3 = random.randint(1, 340-(angle1 + angle2)) + sum_ = angle1 + angle2 + angle3 + angle4 = 360 - sum_ + problem = f"Fourth angle of quadrilateral with angles {angle1} , {angle2}, {angle3} =" + solution = angle4 + return problem, solution + def quadraticEquation(maxVal=100): a = random.randint(1,maxVal) c = random.randint(1,maxVal) @@ -543,6 +725,7 @@ def quadraticEquation(maxVal=100): solution = str([(-b+D)/(2*a),(-b-D)/(2*a)]) return problem,solution + # || Class Instances #Format is: @@ -589,4 +772,13 @@ volumeCylinderGen = Generator("Volume of cylinder", 37, "Volume of cylinder with surfaceAreaConeGen = Generator("Surface Area of cone", 38, "Surface area of cone with height = a units and radius = b units is","c units^2", surfaceAreaCone) volumeConeGen = Generator("Volume of cone", 39, "Volume of cone with height = a units and radius = b units is","c units^3", volumeCone) commonFactors = Generator("Common Factors", 40, "Common Factors of {a} and {b} = ","[c, d, ...]",commonFactorsFunc) -quadraticEquationSolve = Generator("Quadratic Equation", 41, "Find the zeros {x1,x2} of the quadratic equation ax^2+bx+c=0", "x1,x2", quadraticEquation) +intersectionOfTwoLines = Generator("Intersection of Two Lines", 41, "Find the point of intersection of the two lines: y = m1*x + b1 and y = m2*x + b2", "(x, y)", intersectionOfTwoLinesFunc) +permutations= Generator("Permutations",42, "Total permutations of 4 objects at a time from 10 objects is","5040", permutationFunc) +vectorCross = Generator("Cross Product of 2 Vectors", 43, "a X b = ", "c", vectorCrossFunc) +compareFractions=Generator("Compare Fractions",44,"Which symbol represents the comparison between a/b and c/d?",">/ maxAddend) + problem, solution = additionFunc(maxSum, maxAddend) + assert eval(problem[:-1]) == int(solution) + + +@given(maxMinuend=st.integers(min_value=1), maxDiff=st.integers(min_value=1)) +def test_subtractionFunc(maxMinuend, maxDiff): + assume(maxMinuend > maxDiff) + problem, solution = subtractionFunc(maxMinuend, maxDiff) + assert eval(problem[:-1]) == int(solution) + + +@given(maxRes=st.integers(min_value=1), maxMulti=st.integers(min_value=1)) +def test_multiplicationFunc(maxRes, maxMulti): + assume(maxRes > maxMulti) + problem, solution = multiplicationFunc(maxRes, maxMulti) + assert eval(problem[:-1]) == int(solution) + + +@given(maxRes=st.integers(min_value=1), maxDivid=st.integers(min_value=1)) +def test_divisionFunc(maxRes, maxDivid): + assume(maxRes > maxDivid) + problem, solution = divisionFunc(maxRes, maxDivid) + assert eval(problem[:-1]) == float(solution) + + +@given(maxRes=st.integers(min_value=1), maxModulo=st.integers(min_value=1)) +def test_moduloFunc(maxRes, maxModulo): + assume(maxRes > maxModulo) + problem, solution = moduloFunc(maxRes, maxModulo) + assert eval(problem[:-1]) == int(solution) + + +@given(minNo=st.integers(min_value=1), maxNo=st.integers(min_value=1, max_value=2 ** 50)) +def test_squareRootFunc(minNo, maxNo): + assume(maxNo > minNo) + problem, solution = squareRootFunc(minNo, maxNo) + assert eval(problem[:-1]) == float(solution)