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 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_ng_config(): """Test that the NumericalGrader config bars unwanted entries""" expect = "not a valid value for dictionary value @ data\['failable_evals'\]. Got 1" with raises(Error, match=expect): NumericalGrader(answers="1", failable_evals=1) expect = "not a valid value for dictionary value @ data\['samples'\]. Got 2" with raises(Error, match=expect): NumericalGrader(answers="1", samples=2) expect = "not a valid value for dictionary value @ data\['variables'\]. Got \['x'\]" with raises(Error, match=expect): NumericalGrader(answers="1", variables=["x"]) expect = "not a valid value for dictionary value @ data\['sample_from'\]. " + \ "Got {'x': RealInterval\({'start': 1, 'stop': 5}\)}" with raises(Error, match=expect): NumericalGrader(answers="1", sample_from={"x": RealInterval()}) expect = "not a valid value for dictionary value @ data\['user_functions'\]\['f'\]. " + \ "Got RandomFunction" with raises(Error, match=expect): NumericalGrader(answers="1", user_functions={"f": RandomFunction()}) expect = "not a valid value for dictionary value @ data\['user_functions'\]\['f'\]. " + \ "Got \[<ufunc 'sin'>, <ufunc 'cos'>\]" with raises(Error, match=expect): NumericalGrader(answers="1", user_functions={"f": [np.sin, np.cos]})
def test_ng_config(): """Test that the NumericalGrader config bars unwanted entries""" expect = r"not a valid value for dictionary value @ data\[u?'failable_evals'\]. Got 1" with raises(Error, match=expect): NumericalGrader(answers="1", failable_evals=1) expect = r"not a valid value for dictionary value @ data\[u?'samples'\]. Got 2" with raises(Error, match=expect): NumericalGrader(answers="1", samples=2) expect = (r"length of value must be at most 0 for dictionary value " r"@ data\[u?'variables'\]. Got \[u?'x'\]") with raises(Error, match=expect): NumericalGrader(answers="1", variables=["x"]) expect = ( r"extra keys not allowed @ data\[u?'sample_from'\]\[u?'x'\]. Got " r"RealInterval\({u?'start': 1, u?'stop': 5}\)") with raises(Error, match=expect): NumericalGrader(answers="1", sample_from={"x": RealInterval()}) expect = ( r"not a valid value for dictionary value @ data\[u?'user_functions'\]\[u?'f'\]. " r"Got RandomFunction") with raises(Error, match=expect): NumericalGrader(answers="1", user_functions={"f": RandomFunction()}) expect = (r"not a valid value for dictionary value @ data\[u?'user_functions'\]\[u?'f'\]. " + \ r"Got \[<ufunc 'sin'>, <ufunc 'cos'>\]") with raises(Error, match=expect): NumericalGrader(answers="1", user_functions={"f": [np.sin, np.cos]})
def test_fg_sampling(): """Test various sampling methods in FormulaGrader""" grader = FormulaGrader( answers="x^2+y^2+z^2", variables=['x', 'y', 'z', 'w'], sample_from={ 'x': 2, 'y': (1, 3, 5), 'z': [1, 5] } ) assert grader(None, 'x^2+y^2+z^2')['ok'] assert isinstance(grader.config["sample_from"]['x'], DiscreteSet) assert isinstance(grader.config["sample_from"]['y'], DiscreteSet) assert isinstance(grader.config["sample_from"]['z'], RealInterval) assert isinstance(grader.config["sample_from"]['w'], RealInterval) with raises(MultipleInvalid, match="extra keys not allowed @ data\['w'\]"): grader = FormulaGrader(variables=['x'], sample_from={'w': 2}) grader = FormulaGrader( answers="z^2", variables=['z'], sample_from={'z': ComplexSector()} ) assert grader(None, '(z-1)*(z+1)+1')['ok'] grader = FormulaGrader( answers="z^2", variables=['z'], sample_from={'z': ComplexRectangle()} ) assert grader(None, '(z-1)*(z+1)+1')['ok'] grader = FormulaGrader( answers="z^2", variables=['z'], sample_from={'z': IntegerRange()} ) assert grader(None, '(z-1)*(z+1)+1')['ok'] grader = FormulaGrader( answers="z^2", variables=['z'], sample_from={'z': RealInterval()} ) assert grader(None, '(z-1)*(z+1)+1')['ok'] grader = FormulaGrader( answers="z^2", variables=['z'], sample_from={'z': DiscreteSet((1, 3, 5))} ) assert grader(None, '(z-1)*(z+1)+1')['ok']
def test_identity_multiples(): # Test shape, identity times constant, MathArray shapes = tuple(range(2, 5)) samples = ([-1, 1], RealInterval(), ComplexRectangle()) for shape in shapes: for sample in samples: matrices = IdentityMatrixMultiples(dimension=shape, sampler=sample) m = matrices.gen_sample() assert m.shape == (shape, shape) assert np.array_equal(m, m[0, 0] * np.eye(shape)) assert isinstance(m, MathArray)
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(): """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()
def test_real_interval(): """Tests the RealInterval class""" start = random.random() * 20 - 10 stop = random.random() * 20 - 10 if start > stop: start, stop = stop, start # Right way around ri = RealInterval(start=start, stop=stop) for i in range(10): assert start <= ri.gen_sample() <= stop # Wrong way around ri = RealInterval(start=stop, stop=start) for i in range(10): assert start <= ri.gen_sample() <= stop # In a list ri = RealInterval([start, stop]) for i in range(10): assert start <= ri.gen_sample() <= stop # No arguments ri = RealInterval() for i in range(10): assert 1 <= ri.gen_sample() <= 5 # Rejects tuples with raises(Error, match=r"expected a dictionary. Got \(1, 3\)"): RealInterval((1, 3))