def check_response(self, answer, student_input, **kwargs): try: with MathArray.enable_negative_powers(self.config['negative_powers']): result = super(MatrixGrader, self).check_response(answer, student_input, **kwargs) except ShapeError as err: if self.config['suppress_matrix_messages']: return {'ok': False, 'msg': '', 'grade_decimal': 0} elif self.config['shape_errors']: raise else: return {'ok': False, 'msg': err.message, 'grade_decimal': 0} except InputTypeError as err: if self.config['suppress_matrix_messages']: return {'ok': False, 'msg': '', 'grade_decimal': 0} elif self.config['answer_shape_mismatch']['is_raised']: raise else: return {'ok': False, 'grade_decimal': 0, 'msg': err.message} except (ArgumentShapeError, MathArrayError) as err: # If we're using matrix quantities for noncommutative scalars, we # might get an ArgumentShapeError from using functions of matrices, # or a MathArrayError from taking a funny power of a matrix. # Suppress these too. if self.config['suppress_matrix_messages']: return {'ok': False, 'msg': '', 'grade_decimal': 0} raise return result
def random_function(*args): """Function that generates the random values""" # Check that the dimensions are correct if len(args) != input_dim: msg = "Expected {} arguments, but received {}".format( input_dim, len(args)) raise ConfigError(msg) # Turn the inputs into an array xvec = np.array(args) # Repeat it into the shape of A, B and C xarray = np.tile(xvec, (output_dim, num_terms, 1)) # Compute the output matrix output = A * np.sin(B * xarray + C) # Sum over the j and k terms # We have an old version of numpy going here, so we can't use # fullsum = np.sum(output, axis=(1, 2)) fullsum = np.sum(np.sum(output, axis=2), axis=1) # Scale and translate to fit within center and amplitude fullsum = fullsum * self.config["amplitude"] / self.config[ "num_terms"] fullsum += self.config["center"] # Return the result return MathArray(fullsum) if output_dim > 1 else fullsum[0]
def gen_sample(self): """ Generates an array sample and returns it as a MathArray. This calls generate_sample, which is the routine that should be subclassed if needed, rather than this one. """ array = self.generate_sample() return MathArray(array)
def gen_sample(self): """ Generates an identity matrix of specified dimension multiplied by a random scalar """ # Sample the multiplicative constant scaling = self.config['sampler'].gen_sample() # Create the numpy matrix array = scaling * np.eye(self.config['dimension']) # Return the result as a MathArray return MathArray(array)
def gen_sample(self): """ Generates a random matrix of shape and norm determined by config. """ desired_norm = self.norm.gen_sample() # construct an array with entries in [-0.5, 0.5) array = np.random.random_sample(self.config['shape']) - 0.5 actual_norm = np.linalg.norm(array) # convert the array to a matrix with desired norm return MathArray(array) * desired_norm / actual_norm
def validate_student_input_shape(student_input, expected_shape, detail): """ Checks that student_input has expected_shape and raises a ShapeError if it does not. Arguments: student_input (number | MathArray): The numerically-sampled student input expected_shape (tuple): A numpy shape tuple detail (None|'shape'|'type') detail-level of ShapeError message """ try: input_shape = student_input.shape except AttributeError: if isinstance(student_input, Number): input_shape = tuple() else: raise if expected_shape == input_shape: return True if detail is None: raise InputTypeError('') if detail == 'shape': expected = MathArray.get_description(expected_shape) received = MathArray.get_description(input_shape) else: expected = MathArray.get_shape_name(len(expected_shape)) received = MathArray.get_shape_name(len(input_shape)) if detail != 'shape' and expected == received: msg = ("Expected answer to be a {0}, but input is a {1} " "of incorrect shape".format(expected, received)) else: msg = ("Expected answer to be a {0}, but input is a {1}".format( expected, received)) raise InputTypeError(msg)
def check_response(self, answer, student_input, **kwargs): try: with MathArray.enable_negative_powers( self.config['negative_powers']): result = super(MatrixGrader, self).check_response(answer, student_input, **kwargs) except ShapeError as err: if self.config['shape_errors']: raise else: return {'ok': False, 'msg': err.message, 'grade_decimal': 0} except InputTypeError as err: if self.config['answer_shape_mismatch']['is_raised']: raise else: return {'ok': False, 'grade_decimal': 0, 'msg': err.message} return result