Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Namesto GeneratedDataIncorrect uporabi validate #91

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Za dodajanje nove vrste problema je potrebno:
- V podrazredu `Meta` definirati spremenljivko `verbose_name` s pravilnim prikazom imena problema.
- Definirati metodo `generate`, ki vrne slovar podatkov, ki jih lahko kasneje uporabite v navodilu in rešitvi naloge.

V metodi `generate` naključne vrednosti izbirate s pomočjo funkcij iz knjižnice `random`. Za nastavitev semena generatorja psevdonaključnih števil vam ni treba skrbeti. Če želite v problemu delati s simbolnimi izrazi, uporabite knjižnico `sympy`. Če želite lepo rešitev, je običajno bolje, da generirate najprej rešitev in nato nalogo, na primer najprej ničle polinoma in iz njih koeficiente ter ne obratno. Včasih se to ne da in za generiranje lepe rešitve potrebujete več poskusov. V tem primeru uporabite izjemo `GeneratedDataIncorrect`, ki jo sprožite, kadar podatki niso ustrezni. V tem primeru bo program izbral novo seme generatorja ter nalogo poskusil sestaviti znova.
V metodi `generate` naključne vrednosti izbirate s pomočjo funkcij iz knjižnice `random`. Za nastavitev semena generatorja psevdonaključnih števil vam ni treba skrbeti. Če želite v problemu delati s simbolnimi izrazi, uporabite knjižnico `sympy`. Če želite lepo rešitev, je običajno bolje, da generirate najprej rešitev in nato nalogo, na primer najprej ničle polinoma in iz njih koeficiente ter ne obratno. Včasih se to ne da in za generiranje lepe rešitve potrebujete več poskusov. V tem primeru uporabite metodo `validate`, ki preveri, ali so podatki ustrezni. V tem primeru bo program izbral novo seme generatorja ter nalogo poskusil sestaviti znova.

Potem ko uspešno napišete tak razred, poženite ukaza:

Expand Down
10 changes: 5 additions & 5 deletions nadlogar/problems/models/eksponentna_funkcija.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import sympy

from .meta import GeneratedDataIncorrect, Problem
from .meta import Problem


def naredi_eksponentno(do=3, cela_osnova=False, premik=0):
Expand Down Expand Up @@ -93,8 +93,8 @@ def generate(self):
zamik_clena2 = random.choice([-3, -2, -1, 1, 2, 3])
k_clena2 = random.choice([1, 2, 3, -1, -2, -3])
resitev = random.choice([-1, 0, 1, 2, 3])
if not (-2 < (resitev + zamik_clena1) and -2 < (resitev + zamik_clena2)):
raise GeneratedDataIncorrect
self.validate(-2 < (resitev + zamik_clena1))
self.validate(-2 < (resitev + zamik_clena2))
vrednost = sympy.Rational(
osnova ** (resitev + zamik_clena1)
+ k_clena2 * (osnova) ** (resitev + zamik_clena2)
Expand Down Expand Up @@ -161,6 +161,6 @@ def generate(self):
rational=True,
),
)
if not (max([abs(k_osnove2_levi), abs(k_osnove2_desni)]) < 50):
raise GeneratedDataIncorrect # Zagotovi, da v enačbi ne nastopajo prevelike vrednosti.
# Zagotovi, da v enačbi ne nastopajo prevelike vrednosti.
self.validate(max([abs(k_osnove2_levi), abs(k_osnove2_desni)]) < 50)
return {"enacba": sympy.latex(enacba), "resitev": sympy.latex(resitev)}
8 changes: 3 additions & 5 deletions nadlogar/problems/models/kompleksna.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sympy
from django.db import models

from .meta import GeneratedDataIncorrect, Problem
from .meta import Problem


def generiraj_kompleksna_stevila(kolicina):
Expand All @@ -17,10 +17,8 @@ def generiraj_kompleksna_stevila(kolicina):
)
stevila = [r + i * sympy.I for r, i in zip(stevila_r, stevila_i)]

if len(stevila) != len(
set(stevila)
): # preveri, da so vsa števila medsebojno različna
raise GeneratedDataIncorrect
# preveri, da so vsa števila medsebojno različna
Problem.validate(len(stevila) == len(set(stevila)))

if kolicina == 1:
stevila = stevila[0]
Expand Down
48 changes: 20 additions & 28 deletions nadlogar/problems/models/kvadratna.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from django.db import models

from .linearna import seznam_polovick, seznam_tretinj, skozi_tocki
from .meta import GeneratedDataIncorrect, Problem
from .meta import Problem


def nicelna_oblika(od=-5, do=5, risanje=False):
Expand Down Expand Up @@ -127,12 +127,12 @@ class Meta:

def generate(self):
(a, b, c, splosna) = splosna_oblika()
if not self.kompleksni_nicli:
if not (diskriminanta(a, b, c) >= 0 and abs(diskriminanta(a, b, c)) <= 200):
raise GeneratedDataIncorrect
D = diskriminanta(a, b, c)
self.validate(abs(D) <= 200)
if self.kompleksni_nicli:
self.validate(D < 0)
else:
if not (diskriminanta(a, b, c) < 0 and abs(diskriminanta(a, b, c)) <= 200):
raise GeneratedDataIncorrect
self.validate(D >= 0)
[x1, x2] = nicle(a, b, c)
return {
"splosna": sympy.latex(splosna),
Expand Down Expand Up @@ -174,8 +174,7 @@ def generate(self):
# (a, x1, x2, nicelna) = nicelna_oblika(-3, 3, risanje=True)
# funkcija = sympy.expand(nicelna)
# [p, q] = izracunaj_teme(a, -a * (x1 + x2), a * x1 * x2)
# if not (abs(q) <= 5):
# raise GeneratedDataIncorrect
# self.validate(abs(q) <= 5)
# zacetna = funkcija.subs(x, 0)
# return {
# "funkcija": sympy.latex(funkcija),
Expand All @@ -202,8 +201,8 @@ class Meta:
def generate(self):
(a, b, c, splosna) = splosna_oblika()
D = diskriminanta(a, b, c)
if not (D >= 0 and abs(D) <= 200):
raise GeneratedDataIncorrect
self.validate(D >= 0)
self.validate(abs(D) <= 200)
(p, q) = izracunaj_teme(a, b, c)
return {"splosna": sympy.latex(splosna), "p": p, "q": q, "a": a}

Expand Down Expand Up @@ -234,14 +233,12 @@ def generate(self):
koeficienta = sympy.solve(
(a * x1**2 + b * x1 + c - y1, a * x2**2 + b * x2 + c - y2), b, c
)
if not (
koeficienta != []
): # Če ni rešitve vrne prazen seznam in ne praznega slovarja
raise GeneratedDataIncorrect
if not (abs(koeficienta[b]) < 5 and abs(koeficienta[c]) < 5):
raise GeneratedDataIncorrect
if not (abs(koeficienta[b]).q < 5 and abs(koeficienta[c]).q < 5):
raise GeneratedDataIncorrect
# Če ni rešitve vrne prazen seznam in ne praznega slovarja
self.validate(koeficienta != [])
self.validate(abs(koeficienta[b]) < 5)
self.validate(abs(koeficienta[c]) < 5)
self.validate(abs(koeficienta[b]).q < 5)
self.validate(abs(koeficienta[c]).q < 5)
kvadratna = a * x**2 + koeficienta[b] * x + koeficienta[c]
return {
"parabola": sympy.latex(kvadratna),
Expand Down Expand Up @@ -280,20 +277,16 @@ def generate(self):
)
else:
primerjava = splosna_oblika()[-1]
if not (splosna1 != primerjava):
raise GeneratedDataIncorrect
self.validate(splosna1 != primerjava)
neenacaj = random.choice(["<", "<=", ">", ">="])
neenakost = sympy.Rel(splosna1, primerjava, neenacaj)
nicli = sympy.solve(sympy.Eq(splosna1, primerjava), x)
if len(nicli) == 0:
pass
else:
if not (
nicli[0].is_real
and abs(max(nicli, key=abs)) < 10
and sympy.denom(max(nicli, key=sympy.denom)) < 20
):
raise GeneratedDataIncorrect
self.validate(nicli[0].is_real)
self.validate(abs(max(nicli, key=abs)) < 10)
self.validate(sympy.denom(max(nicli, key=sympy.denom)) < 20)

resitev = sympy.solveset(neenakost, domain=sympy.S.Reals)
return {"neenakost": sympy.latex(neenakost), "resitev": sympy.latex(resitev)}
Expand Down Expand Up @@ -328,8 +321,7 @@ def generate(self):
x2 = random.randint(-5, 5)

x3 = random.randint(-5, 5)
if not (len({x1, x2, x3}) == 3):
raise GeneratedDataIncorrect
self.validate(len({x1, x2, x3}) == 3)
y1 = funkcija.subs(x, x1)
y2 = funkcija.subs(x, x2)
y3 = funkcija.subs(x, x3)
Expand Down
49 changes: 25 additions & 24 deletions nadlogar/problems/models/linearna.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sympy
from django.db import models

from .meta import GeneratedDataIncorrect, Problem
from .meta import Problem


def seznam_polovick(od=-10, do=10):
Expand Down Expand Up @@ -140,17 +140,19 @@ def generate(self):
y1 = random.choice(seznam_polovick(-5, 5) + seznam_tretinj(-5, 5))
x2 = random.randint(-10, 10)
y2 = random.randint(-10, 10)
if not (
x1 != x2 and y1 != y2
): # Preveri, da sta 2 različni točki in nista vzporedni osem
raise GeneratedDataIncorrect
if not skozi_tocki(x1, y1, x2, y2)[0] in [
sympy.Rational(x, y)
for x in range(0, 6)
for y in range(0, 2 * 10)
if (x != 0 and y != 0)
]: # Lepše rešitve
raise GeneratedDataIncorrect
# Preveri, da sta 2 različni točki in nista vzporedni osem
self.validate(x1 != x2)
self.validate(y1 != y2)
# Lepše rešitve
self.validate(
skozi_tocki(x1, y1, x2, y2)[0]
in [
sympy.Rational(x, y)
for x in range(0, 6)
for y in range(0, 2 * 10)
if (x != 0 and y != 0)
]
)
premica = sympy.latex(skozi_tocki(x1, y1, x2, y2)[-1])
return {
"x1": sympy.latex(x1),
Expand Down Expand Up @@ -179,8 +181,8 @@ def generate(self):
y1 = izberi_koordinato()
x2 = izberi_koordinato()
y2 = izberi_koordinato()
if not (x1 != x2 and y1 != y2):
raise GeneratedDataIncorrect
self.validate(x1 != x2)
self.validate(y1 != y2)
razdalja = sympy.latex(razdalja_med_tockama(x1, y1, x2, y2))
return {
"x1": sympy.latex(x1),
Expand Down Expand Up @@ -256,8 +258,9 @@ def generate(self):
y3 = 0
x = sympy.symbols("x")
y = sympy.symbols("y")
if not (x2 != x1 and x2 != x3): # premici sta vzporedni
raise GeneratedDataIncorrect
# premici sta vzporedni
self.validate(x2 != x1)
self.validate(x2 != x3)
if x2 == x1:
premica1 = sympy.Eq(x, x1)
else:
Expand Down Expand Up @@ -347,8 +350,7 @@ def generate(self):

x1 = random.choice(seznam_polovick(-3, 3) + seznam_tretinj(-3, 3))
x2 = random.choice(seznam_polovick(-3, 3) + seznam_tretinj(-3, 3))
if not (x1 != x2):
raise GeneratedDataIncorrect
self.validate(x1 != x2)
y1 = k * x1 + n
y2 = k * x2 + n

Expand Down Expand Up @@ -443,8 +445,8 @@ def generate(self):
b = random.choice(izborCela)
d = random.choice(izborCela)
e = random.choice(izborCela)
if not ((a, b) != (d, e) and (x1 != 0 or y1 != 0)):
raise GeneratedDataIncorrect
self.validate((a, b) != (d, e))
self.validate((x1 != 0 or y1 != 0))
c = a * x1 + b * y1
f = d * x1 + e * y1
enacba1 = a * x + b * y
Expand Down Expand Up @@ -498,7 +500,7 @@ def generate(self):
koef_y3 = random.choice(izborCela)
koef_z3 = random.choice(izborCela)

if not (
self.validate(
len(
{
(koef_x1, koef_y1, koef_z1),
Expand All @@ -507,9 +509,8 @@ def generate(self):
}
)
== 3
and (x1 != 0 or y1 != 0 or z1 != 0)
):
raise GeneratedDataIncorrect
)
self.validate((x1 != 0 or y1 != 0 or z1 != 0))

# vrednosti enačb in enačbe
vrednost1 = koef_x1 * x1 + koef_y1 * y1 + koef_z1 * z1
Expand Down
27 changes: 12 additions & 15 deletions nadlogar/problems/models/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,10 @@ class Template(string.Template):
delimiter = "@"


class GeneratedDataIncorrect(Exception):
"""An exception that is raised when a generator failed to produce proper problem data.

Sometimes we can determine only after a few steps that the problem data in not suitable.
For example, the zeroes of a polynomial may be sufficiently small, but after expanding the
polynomial, the coefficients end up too large. In this case, we can raise
GeneratedDataIncorrect to restart the generator with a different random seed.
"""
class _GeneratedDataIncorrect(Exception):
# This is a private exception that is used to restart the generator with a different
# random seed. It is not meant to be used directly, but rather through the
# validate method.

pass

Expand Down Expand Up @@ -146,15 +142,16 @@ def generate(self):
# generate anything.
raise NotImplementedError

@classmethod
def validate(self, condition):
"""Raises GeneratedDataIncorrect if the condition is not met.
"""Validates the generated data.

This is used to validate the generated data. If the data is not suitable, we
raise GeneratedDataIncorrect to restart the generator with a different random
seed. If the data is suitable, we do nothing.
"""
Sometimes we can determine only after a few steps that the problem data in not suitable.
For example, the zeroes of a polynomial may be sufficiently small, but after expanding the
polynomial, the coefficients end up too large. In this case, we can raise a private exception
to restart the generator with a different random seed."""
if not condition:
raise GeneratedDataIncorrect
raise _GeneratedDataIncorrect

def _generate_data(self, seed):
"""Generates a list of problem data for all subproblems.
Expand All @@ -177,7 +174,7 @@ def _generate_data(self, seed):
if new_data not in data:
data.append(new_data)
break
except GeneratedDataIncorrect:
except _GeneratedDataIncorrect:
pass
return data

Expand Down
6 changes: 3 additions & 3 deletions nadlogar/problems/models/mnozice.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sympy
from django.db import models

from .meta import GeneratedDataIncorrect, Problem
from .meta import Problem


class ElementiMnozice(Problem):
Expand Down Expand Up @@ -123,10 +123,10 @@ def generate(self):
k = sympy.symbols("k")
a = random.randint(2, 5)
b = random.randint(-4, 4)
self.validate(abs(b) != a)
c = random.randint(2, 5)
d = random.randint(-4, 4)
if abs(b) == a or abs(d) == c:
raise GeneratedDataIncorrect
self.validate(abs(d) != c)
velikost_univerzalne = random.randint(12, 20)
univerzalna = sympy.FiniteSet(*range(1, velikost_univerzalne + 1))
navodilo_A = a * k + b
Expand Down
17 changes: 7 additions & 10 deletions nadlogar/problems/models/naravna.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sympy
from django.db import models

from .meta import GeneratedDataIncorrect, Problem
from .meta import Problem


class DeliteljVeckratnik(Problem):
Expand Down Expand Up @@ -36,12 +36,11 @@ class Meta:
def generate(self):
stevilo1 = random.randint(self.minimalna_vrednost, self.maksimalna_vrednost)
stevilo2 = random.randint(self.minimalna_vrednost, self.maksimalna_vrednost)
if not (
self.validate(stevilo1 != stevilo2)
self.validate(
max(*sympy.factorint(stevilo1).keys(), *sympy.factorint(stevilo2).keys())
<= self.maksimalni_prafaktor
and stevilo1 != stevilo2
):
raise GeneratedDataIncorrect
)
najvecji_delitelj = sympy.gcd(stevilo1, stevilo2)
najmanjsi_veckratnik = sympy.lcm(stevilo1, stevilo2)

Expand All @@ -65,11 +64,9 @@ class Meta:
def generate(self):
stevilo_malo = random.randint(50, 199)
stevilo_veliko = random.randint(200, 1000)
if not (
stevilo_veliko % stevilo_malo != 0
and stevilo_malo % (stevilo_veliko % stevilo_malo) != 0
): # Da se ne konča že v prvih dveh korakih
raise GeneratedDataIncorrect
# Da se ne konča že v prvih dveh korakih
self.validate(stevilo_veliko % stevilo_malo != 0)
self.validate(stevilo_malo % (stevilo_veliko % stevilo_malo) != 0)
najvecji_delitelj = sympy.gcd(stevilo_malo, stevilo_veliko)
return {
"stevilo1": stevilo_malo,
Expand Down
Loading