def generate_operand(rows, columns): global _n _n += 1 if columns == rows: if rows == 1: return # scalar operand = ae.Matrix('M{}'.format(_n), size=(rows, columns)) operand.set_property(properties.FULL_RANK) # include "no property" if random.random() > 0.25: operand.set_property(random.choices([properties.DIAGONAL, properties.LOWER_TRIANGULAR, properties.UPPER_TRIANGULAR, properties.SYMMETRIC, properties.SPD])[0]) return operand elif columns == 1: return ae.Vector('v{}'.format(_n), size=(rows, columns)) elif rows == 1: return ae.Vector('v{}'.format(_n), size=(rows, columns)) else: operand = ae.Matrix('M{}'.format(_n), size=(rows, columns)) operand.set_property(properties.FULL_RANK) return operand
def generate_matrix(rows, columns): global _counter _counter += 1 operand = ae.Matrix("M{}".format(_counter), (rows, columns)) operand.set_property(properties.FULL_RANK) if rows == columns and random.random() > 0.25: operand.set_property( random.choice([ properties.DIAGONAL, properties.LOWER_TRIANGULAR, properties.UPPER_TRIANGULAR, properties.SYMMETRIC, properties.SPD ])) return operand
def randomize_sizes(expr, rows=None, cols=None): can_change = False if rows is None: rows = random_dimension() if cols is None: can_change = True cols = random_dimension() if isinstance(expr, ae.Symbol): if rows == 1 or cols == 1: if rows == cols: return ae.Scalar(expr.name.replace('M', 'a')) else: return ae.Vector(expr.name.replace('M', 'v'), (rows, cols)) return ae.Matrix(expr.name, (rows, cols)) try: if isinstance(expr, ae.Times): operands = [] new_rows = rows for operand in expr.operands[:-1]: new_cols = random_dimension() try: operands.append( randomize_sizes(operand, new_rows, new_cols)) new_rows = new_cols except NeedQuadratic: operands.append( randomize_sizes(operand, new_rows, new_rows)) try: operands.append( randomize_sizes(expr.operands[-1], new_rows, cols)) except NeedQuadratic: operands.append( randomize_sizes(expr.operands[-1], new_rows, new_rows)) return ae.Times(*operands) if isinstance(expr, ae.Transpose): return ae.Transpose(randomize_sizes(expr.operand, cols, rows)) if isinstance(expr, (ae.Inverse, ae.InverseTranspose)): if rows != cols: # Inversion needs a quadratic matrix or a scalar raise NeedQuadratic() return type(expr)(randomize_sizes(expr.operand, rows, rows)) if isinstance(expr, ae.Operator): return type(expr)(*(randomize_sizes(operand, rows, cols) for operand in expr.operands)) assert False, "Unreachable" except NeedQuadratic: if not can_change: raise return randomize_sizes(expr, rows, rows)
def generate_equation(n_ops): expr_size = operand_sizes() out = ae.Matrix("out", expr_size) expr = simplify(generate_expression(n_ops, expr_size)) return aeq.Equations(ae.Equal(out, expr))
def matrix_chain_generator(): while True: # for _ in range(20): # expression_strategy.example() # generate_matrix_chain() length = random.randrange(4, 10) sizes = [] if 0.95 <= random.random(): sizes.append(1) else: sizes.append(matrix_size()) for i in range(length): rand = random.random() if 0.6 <= rand < 0.95: # square sizes.append(sizes[i]) elif 0.95 <= rand: # vector sizes.append(1) else: # non-square sizes.append(matrix_size()) # print(sizes) operands = [] restart = False for rows, columns in window(sizes): if rows == columns: if rows == 1: restart = True break # operands.append(None) # error op = random.choices([ae.Identity, ae.Transpose, ae.Inverse, ae.InverseTranspose], weights=[2, 1, 1, 1])[0] operands.append(op(generate_operand(rows, columns))) elif rows == 1: operands.append(ae.Transpose(generate_operand(columns, rows))) elif columns == 1: operands.append(generate_operand(rows, columns)) else: op = random.choices([ae.Identity, ae.Transpose], weights=[3, 1])[0] if op == ae.Transpose: operands.append(op(generate_operand(columns, rows))) else: operands.append(op(generate_operand(rows, columns))) if restart: continue # print(operands) expr = ae.Times(*operands) expr = simplify(expr) # print(expr) # print(expr.size) # print((sizes[0], sizes[-1])) if expr.has_property(properties.MATRIX): lhs = ae.Matrix('X'.format(_n), size=(sizes[0], sizes[-1])) elif expr.has_property(properties.VECTOR): lhs = ae.Vector('x'.format(_n), size=(sizes[0], sizes[-1])) yield Equations(ae.Equal(lhs, expr))
def next_matrix(): global _n _n += 1 return ae.Matrix('M{}'.format(_n), size=(5, 5))