def test_instructor_vars():
    """Ensures that instructor variables are not available to students"""
    grader = FormulaGrader(
        answers='sin(x)/cos(x)',
        variables=['x', 's', 'c'],
        numbered_vars=['y'],
        sample_from={
            'x': [-3.14159, 3.14159],
            's': DependentSampler(depends=["x"], formula="sin(x)"),
            'c': DependentSampler(depends=["x"], formula="cos(x)")
        },
        instructor_vars=['x', 'pi', 'y_{0}',
                         'nothere']  # nothere will be ignored
    )

    assert grader(None, 's/c')['ok']
    assert not grader(None, 'y_{1}')['ok']
    with raises(UndefinedVariable,
                match="'x' not permitted in answer as a variable"):
        grader(None, 'tan(x)')
    with raises(UndefinedVariable,
                match="'pi' not permitted in answer as a variable"):
        grader(None, 'pi')
    with raises(UndefinedVariable,
                match=r"'y_\{0\}' not permitted in answer as a variable"):
        grader(None, 'y_{0}')
def test_overriding_constant_with_dependent_sampling():
    symbols = ['a', 'b', 'c']
    samples = 1
    sample_from = {
        'a': RealInterval([10, 10]),
        'b': DependentSampler(depends=["a"], formula="a+1"),
        'c': DependentSampler(depends=["b"], formula="b+1")
    }
    funcs, suffs = {}, {}
    consts = {'unity': 1, 'b': 3.14}
    result = gen_symbols_samples(symbols, samples, sample_from, funcs, suffs, consts)[0]
    a, b, c = [result[sym] for sym in 'abc']

    assert a == 10
    assert b == 11
    assert c == 12
def test_dependent_sampler_infers_dependence():
    sampler = DependentSampler(formula="a+1")
    assert sampler.config['depends'] == ['a']

    sampler = DependentSampler(formula="x^2+y^2+sin(c)")
    assert set(sampler.config['depends']) == set(['x', 'y', 'c'])

    # Test that 'depends' is now ignored
    symbols = ["x", "y"]
    samples = 1
    sample_from = {
        'x': DependentSampler(depends=["y"], formula="1"),
        'y': DependentSampler(depends=["x"], formula="1")
    }
    funcs, suffs, consts = {}, {}, {}
    # This does NOT raise an error; the depends entry is ignored
    gen_symbols_samples(symbols, samples, sample_from, funcs, suffs, consts)
Exemplo n.º 4
0
def test_dependent_sampler():
    """Tests the DependentSampler class"""
    # Test basic usage and multiple samples
    result = gen_symbols_samples(
        ["a", "b"], 2, {
            'a': IntegerRange([1, 1]),
            'b': DependentSampler(depends=["a"], formula="a+1")
        })
    assert result == [{"a": 1, "b": 2.0}, {"a": 1, "b": 2.0}]

    result = gen_symbols_samples(
        ["a", "b", "c", "d"], 1, {
            'a': RealInterval([1, 1]),
            'd': DependentSampler(depends=["c"], formula="c+1"),
            'c': DependentSampler(depends=["b"], formula="b+1"),
            'b': DependentSampler(depends=["a"], formula="a+1")
        })[0]
    assert result["b"] == 2 and result["c"] == 3 and result["d"] == 4

    result = gen_symbols_samples(
        ["x", "y", "z", "r"], 1, {
            'x':
            RealInterval([-5, 5]),
            'y':
            RealInterval([-5, 5]),
            'z':
            RealInterval([-5, 5]),
            'r':
            DependentSampler(depends=["x", "y", "z"],
                             formula="sqrt(x^2+y^2+z^2)")
        })[0]
    assert result["x"]**2 + result["y"]**2 + result["z"]**2 == approx(
        result["r"]**2)

    with raises(ConfigError,
                match="Circularly dependent DependentSamplers detected: x, y"):
        gen_symbols_samples(
            ["x", "y"], 1, {
                'x': DependentSampler(depends=["y"], formula="1"),
                'y': DependentSampler(depends=["x"], formula="1")
            })

    with raises(ConfigError,
                match=r"Formula error in dependent sampling formula: 1\+\(2"):
        gen_symbols_samples(
            ["x"], 1, {'x': DependentSampler(depends=[], formula="1+(2")})

    with raises(Exception,
                match="DependentSampler must be invoked with compute_sample."):
        DependentSampler(depends=[], formula="1").gen_sample()
def test_dependentsampler():
    # Ensure that dependentsampler can make use of user-defined functions
    grader = FormulaGrader(
        answers='y',
        variables=['x', 'y'],
        user_functions={'f': lambda x: x**2},
        sample_from={'y': DependentSampler(depends=["x"], formula="f(x)")})
    assert grader(None, 'y')['ok']
    assert grader(None, 'x^2')['ok']
Exemplo n.º 6
0
def test_docs():
    """Make sure that the documentation examples work"""
    # Generate random real numbers between 3 and 7
    sampler = RealInterval(start=3, stop=7)
    # This is equivalent to
    sampler = RealInterval([3, 7])
    # The default is [1, 5]
    sampler = RealInterval()

    # Generate random integers between 3 and 7 inclusive
    sampler = IntegerRange(start=3, stop=7)
    # This is equivalent to
    sampler = IntegerRange([3, 7])
    # The default is [1, 5]
    sampler = IntegerRange()

    # Select random numbers from (1, 3, 5, 7, 9)
    sampler = DiscreteSet((1, 3, 5, 7, 9))
    # Always select 3.5
    sampler = DiscreteSet(3.5)

    # Select random complex numbers from 0 to 1 + i
    sampler = ComplexRectangle(re=[0, 1], im=[0, 1])
    # The default is re=[1, 3], im=[1, 3]
    sampler = ComplexRectangle()

    # Select random complex numbers from inside the unit circle
    sampler = ComplexSector(modulus=[0, 1], argument=[-np.pi, np.pi])
    # The default is modulus=[1, 3], argument=[0, pi/2]
    sampler = ComplexSector()

    # Test dependent sampling
    sampler = DependentSampler(depends=["x", "y", "z"],
                               formula="sqrt(x^2+y^2+z^2)")

    # Select either sin or cos randomly
    functionsampler = SpecificFunctions([np.cos, np.sin])
    # Always select a single lambda function
    functionsampler = SpecificFunctions(lambda x: x * x)

    # Generate a random function
    functionsampler = RandomFunction(center=1, amplitude=2)
    # The default is center=0, amplitude=10
    functionsampler = RandomFunction()

    # Generate a random sinusoid
    functionsampler = RandomFunction(num_terms=1)

    # Generate a function that takes in two values and outputs a 3D vector
    functionsampler = RandomFunction(input_dim=2, output_dim=3)
def test_dependent_sampler():
    """Tests the DependentSampler class"""
    # Test basic usage and multiple samples
    symbols = ["a", "b"]
    samples = 2
    sample_from = {
        'a': IntegerRange([1, 1]),
        'b': DependentSampler(depends=["a"], formula="a+1")
    }
    funcs, suffs, consts = {}, {}, {}
    result = gen_symbols_samples(symbols, samples, sample_from, funcs, suffs, consts)
    assert result == [{"a": 1, "b": 2.0}, {"a": 1, "b": 2.0}]

    symbols = ["a", "b", "c", "d"]
    samples = 1
    sample_from = {
        'a': RealInterval([1, 1]),
        'd': DependentSampler(depends=["c"], formula="c+1"),
        'c': DependentSampler(depends=["b"], formula="b+1"),
        'b': DependentSampler(depends=["a"], formula="a+1")
    }
    funcs, suffs, consts = {}, {}, {}
    result = gen_symbols_samples(symbols, samples, sample_from, funcs, suffs, consts)[0]
    assert result["b"] == 2 and result["c"] == 3 and result["d"] == 4

    symbols = ["x", "y", "z", "r"]
    samples = 1
    sample_from = {
        'x': RealInterval([-5, 5]),
        'y': RealInterval([-5, 5]),
        'z': RealInterval([-5, 5]),
        'r': DependentSampler(depends=["x", "y", "z"], formula="sqrt(x^2+y^2+z^2 + unity)")
    }
    funcs = {'sqrt': lambda x: x**0.5}
    consts = {'unity': 1}
    suffs = {}
    result = gen_symbols_samples(symbols, samples, sample_from, funcs, suffs, consts)[0]
    assert result["x"]**2 + result["y"]**2 + result["z"]**2 + 1 == approx(result["r"]**2)

    symbols = ["x", "y"]
    samples = 1
    sample_from = {
        'x': DependentSampler(depends=["y"], formula="y"),
        'y': DependentSampler(depends=["x"], formula="x")
    }
    funcs, suffs, consts = {}, {}, {}
    with raises(ConfigError, match="Circularly dependent DependentSamplers detected: x, y"):
        gen_symbols_samples(symbols, samples, sample_from, funcs, suffs, consts)

    with raises(ConfigError, match=r"Formula error in dependent sampling formula: 1\+\(2"):
        DependentSampler(formula="1+(2")

    symbols = ["x"]
    samples = 1
    sample_from = {'x': DependentSampler(formula="min(j, i)")}
    with raises(ConfigError, match=r"Formula error in dependent sampling formula: min\(j, i\)"):
        gen_symbols_samples(symbols, samples, sample_from, funcs, suffs, {'i': 1j, 'j': 1j})

    with raises(ConfigError, match=r"DependentSamplers depend on undefined quantities: i, j"):
        gen_symbols_samples(symbols, samples, sample_from, funcs, suffs, consts)

    with raises(Exception, match="DependentSampler must be invoked with compute_sample."):
        DependentSampler(depends=[], formula="1").gen_sample()