def test_batch_generator(): size = 10 batch_size = 3 x = np.arange(size, dtype=np.float32) answer_x = np.arange(batch_size) % size generator = PredefinedGenerator(x) batch_generator = BatchGenerator(generator, batch_size) for _ in range(50): x = batch_generator.get_examples() assert _check_shape_and_grad(batch_generator, batch_size, x) assert _check_iterable_equal(answer_x, x) assert len(batch_generator.cached_xs) <= size + max(size, batch_size) # update answer for next iteration answer_x = (answer_x + batch_size) % size size = 3 batch_size = 10 x = np.arange(size, dtype=np.float32) y = np.arange(size, dtype=np.float32) answer_x = np.arange(batch_size) % size answer_y = np.arange(batch_size) % size generator = PredefinedGenerator(x, y) batch_generator = BatchGenerator(generator, batch_size) for _ in range(50): x, y = batch_generator.get_examples() assert _check_shape_and_grad(batch_generator, batch_size, x, y) assert _check_iterable_equal(answer_x, x) assert _check_iterable_equal(answer_y, y) assert len(batch_generator.cached_xs) <= size + max(size, batch_size) # update answer for next iteration answer_x = (answer_x + batch_size) % size answer_y = (answer_y + batch_size) % size str(batch_generator) repr(batch_generator)
def test_ensemble_generator(): size = 100 generator1 = Generator1D(size) ensemble_generator = EnsembleGenerator(generator1) x = ensemble_generator.get_examples() assert _check_shape_and_grad(ensemble_generator, size, x) old_x = torch.rand(size) old_y = torch.rand(size) old_z = torch.rand(size) generator1 = PredefinedGenerator(old_x) generator2 = PredefinedGenerator(old_y) generator3 = PredefinedGenerator(old_z) ensemble_generator = EnsembleGenerator(generator1, generator2, generator3) x, y, z = ensemble_generator.get_examples() assert _check_shape_and_grad(ensemble_generator, size, x, y, z) assert _check_iterable_equal(old_x, x) assert _check_iterable_equal(old_y, y) assert _check_iterable_equal(old_z, z) old_x = torch.rand(size) old_y = torch.rand(size) generator1 = PredefinedGenerator(old_x) generator2 = PredefinedGenerator(old_y) product_generator = generator1 * generator2 x, y = product_generator.get_examples() assert _check_shape_and_grad(product_generator, size, x, y) assert _check_iterable_equal(old_x, x) assert _check_iterable_equal(old_y, y) str(ensemble_generator) repr(ensemble_generator)
def test_transform_generator(): size = 100 x = np.arange(0, size, dtype=np.float32) x_expected = np.sin(x) generator = PredefinedGenerator(x) transform_generator = TransformGenerator(generator, [torch.sin]) x = transform_generator.get_examples() assert _check_shape_and_grad(transform_generator, size, x) assert _check_iterable_equal(x, x_expected) x = np.arange(0, size, dtype=np.float32) y = np.arange(0, size, dtype=np.float32) z = np.arange(0, size, dtype=np.float32) x_expected = np.sin(x) y_expected = y z_expected = -z generator = PredefinedGenerator(x, y, z) transform_generator = TransformGenerator(generator, [torch.sin, None, lambda a: -a]) x, y, z = transform_generator.get_examples() assert _check_shape_and_grad(transform_generator, size, x, y, z) assert _check_iterable_equal(x, x_expected) assert _check_iterable_equal(y, y_expected) assert _check_iterable_equal(z, z_expected) transform_generator = TransformGenerator(generator, transform=lambda x, y, z: (torch.sin(x), y, -z)) x, y, z = transform_generator.get_examples() assert _check_shape_and_grad(transform_generator, size, x, y, z) assert _check_iterable_equal(x, x_expected) assert _check_iterable_equal(y, y_expected) assert _check_iterable_equal(z, z_expected) print('testing generator name: ', transform_generator)
def test_predefined_generator(): size = 100 old_x = torch.arange(size, dtype=torch.float, requires_grad=False) predefined_generator = PredefinedGenerator(old_x) x = predefined_generator.get_examples() assert _check_shape_and_grad(predefined_generator, size, x) assert _check_iterable_equal(old_x, x) old_x = torch.arange(size, dtype=torch.float, requires_grad=False) old_y = torch.arange(size, dtype=torch.float, requires_grad=True) old_z = torch.arange(size, dtype=torch.float, requires_grad=False) predefined_generator = PredefinedGenerator(old_x, old_y, old_z) x, y, z = predefined_generator.get_examples() assert _check_shape_and_grad(predefined_generator, size, x, y, z) assert _check_iterable_equal(old_x, x) assert _check_iterable_equal(old_y, y) assert _check_iterable_equal(old_z, z) x_list = [i * 2.0 for i in range(size)] y_tuple = tuple([i * 3.0 for i in range(size)]) z_array = np.array([i * 4.0 for i in range(size)]).reshape(-1, 1) w_tensor = torch.arange(size, dtype=torch.float) predefined_generator = PredefinedGenerator(x_list, y_tuple, z_array, w_tensor) x, y, z, w = predefined_generator.get_examples() assert _check_shape_and_grad(predefined_generator, size, x, y, z, w) assert _check_iterable_equal(x_list, x) assert _check_iterable_equal(y_tuple, y) assert _check_iterable_equal(z_array, z) assert _check_iterable_equal(w_tensor, w) str(predefined_generator) repr(predefined_generator)
def test_resample_generator(): size = 100 sample_size = size x_expected = np.arange(size, dtype=np.float32) generator = PredefinedGenerator(x_expected) resample_generator = ResampleGenerator(generator, size=sample_size, replacement=False) x = resample_generator.get_examples() assert _check_shape_and_grad(resample_generator, sample_size, x) # noinspection PyTypeChecker assert _check_iterable_equal(torch.sort(x)[0], x_expected) sample_size = size // 2 x = np.arange(size, dtype=np.float32) y = np.arange(size, size * 2, dtype=np.float32) generator = PredefinedGenerator(x, y) resample_generator = ResampleGenerator(generator, size=sample_size, replacement=False) x, y = resample_generator.get_examples() assert _check_shape_and_grad(resample_generator, sample_size, x, y) assert _check_iterable_equal(x + 100, y) assert len(torch.unique(x.detach())) == len(x) sample_size = size * 3 // 4 x = np.arange(size, dtype=np.float32) y = np.arange(size, size * 2, dtype=np.float32) generator = PredefinedGenerator(x, y) resample_generator = ResampleGenerator(generator, size=sample_size, replacement=True) x, y = resample_generator.get_examples() assert _check_shape_and_grad(resample_generator, sample_size, x, y) assert _check_iterable_equal(x + 100, y) assert len(torch.unique(x.detach())) < len(x) sample_size = size * 2 x = np.arange(size, dtype=np.float32) y = np.arange(size, size * 2, dtype=np.float32) z = np.arange(size * 2, size * 3, dtype=np.float32) generator = PredefinedGenerator(x, y, z) resample_generator = ResampleGenerator(generator, size=sample_size, replacement=True) x, y, z = resample_generator.get_examples() assert _check_shape_and_grad(resample_generator, sample_size, x, y, z) assert _check_iterable_equal(x + 100, y) assert _check_iterable_equal(y + 100, z) assert len(torch.unique(x.detach())) < len(x) str(resample_generator) repr(resample_generator)
def test_filter_generator(): grid = (10, 10) size = 100 x = [i * 1.0 for i in range(size)] filter_fn = lambda a: (a[0] % 2 == 0) filter_fn_2 = lambda a: (a % 2 == 0) x_expected = filter(filter_fn_2, x) generator = PredefinedGenerator(x) filter_generator = FilterGenerator(generator, filter_fn=filter_fn, update_size=True) x = filter_generator.get_examples() assert _check_shape_and_grad(filter_generator, size // 2, x) assert _check_iterable_equal(x_expected, x) x = [i * 1.0 for i in range(size)] y = [-i * 1.0 for i in range(size)] filter_fn = lambda ab: (ab[0] % 2 == 0) & (ab[1] > -size / 2) x_expected, y_expected = list(zip(*filter(filter_fn, zip(x, y)))) generator = PredefinedGenerator(x, y) filter_generator = FilterGenerator(generator, filter_fn) x, y = filter_generator.get_examples() assert _check_shape_and_grad(filter_generator, size // 4, x, y) assert _check_iterable_equal(x_expected, x) assert _check_iterable_equal(y_expected, y) generator = Generator2D(grid) filter_fn = lambda ab: (ab[0] > 0.5) & (ab[1] < 0.5) filter_generator = FilterGenerator(generator, filter_fn) for _ in range(5): x, y = filter_generator.get_examples() assert _check_shape_and_grad(filter_generator, None, x, y) fixed_size = 42 filter_generator = FilterGenerator(generator, filter_fn, size=fixed_size, update_size=False) for _ in range(5): assert _check_shape_and_grad(filter_generator, fixed_size) filter_generator.get_examples() str(filter_generator) repr(filter_generator)
def test_arbitrary_boundary(): def solution_analytical_problem_c(x, y): return np.log(1 + x**2 + y**2) def gradient_solution_analytical_problem_c(x, y): return 2 * x / (1 + x**2 + y**2), 2 * y / (1 + x**2 + y**2), # creating control points for Dirichlet boundary conditions edge_length = 2.0 / np.sin(np.pi / 3) / 4 points_on_each_edge = 11 step_size = edge_length / (points_on_each_edge - 1) direction_theta = np.pi * 2 / 3 left_turn_theta = np.pi * 1 / 3 right_turn_theta = -np.pi * 2 / 3 dirichlet_control_points_problem_c = [] point_x, point_y = 0.0, -1.0 for i_edge in range(6): for i_step in range(points_on_each_edge - 1): dirichlet_control_points_problem_c.append( DirichletControlPoint(loc=(point_x, point_y), val=solution_analytical_problem_c( point_x, point_y))) point_x += step_size * np.cos(direction_theta) point_y += step_size * np.sin(direction_theta) direction_theta += left_turn_theta if (i_edge % 2 == 0) else right_turn_theta # dummy control points to form closed domain radius_circle = 1.0 / np.sin(np.pi / 6) center_circle_x = radius_circle * np.cos(np.pi / 6) center_circle_y = 0.0 dirichlet_control_points_problem_c_dummy = [] for theta in np.linspace(-np.pi * 5 / 6, np.pi * 5 / 6, 60): point_x = center_circle_x + radius_circle * np.cos(theta) point_y = center_circle_y + radius_circle * np.sin(theta) dirichlet_control_points_problem_c_dummy.append( DirichletControlPoint(loc=(point_x, point_y), val=solution_analytical_problem_c( point_x, point_y))) # all Dirichlet control points dirichlet_control_points_problem_c_all = \ dirichlet_control_points_problem_c + dirichlet_control_points_problem_c_dummy # creating control points for Neumann boundary condition edge_length = 2.0 / np.sin(np.pi / 3) / 4 points_on_each_edge = 11 step_size = edge_length / (points_on_each_edge - 1) normal_theta = np.pi / 6 direction_theta = -np.pi * 1 / 3 left_turn_theta = np.pi * 1 / 3 right_turn_theta = -np.pi * 2 / 3 neumann_control_points_problem_c = [] point_x, point_y = 0.0, 1.0 for i_edge in range(6): normal_x = np.cos(normal_theta) normal_y = np.sin(normal_theta) # skip the points on the "tip", their normal vector is undefined? point_x += step_size * np.cos(direction_theta) point_y += step_size * np.sin(direction_theta) for i_step in range(points_on_each_edge - 2): grad_x, grad_y = gradient_solution_analytical_problem_c( point_x, point_y) neumann_val = grad_x * normal_x + grad_y * normal_y neumann_control_points_problem_c.append( NeumannControlPoint(loc=(point_x, point_y), val=neumann_val, normal_vector=(normal_x, normal_y))) point_x += step_size * np.cos(direction_theta) point_y += step_size * np.sin(direction_theta) direction_theta += left_turn_theta if (i_edge % 2 == 0) else right_turn_theta normal_theta += left_turn_theta if (i_edge % 2 == 0) else right_turn_theta # dummy control points to form closed domain radius_circle = 1.0 / np.sin(np.pi / 6) center_circle_x = -radius_circle * np.cos(np.pi / 6) center_circle_y = 0.0 neumann_control_points_problem_c_dummy = [] for theta in np.linspace(np.pi * 1 / 6, np.pi * 11 / 6, 60): point_x = center_circle_x + radius_circle * np.cos(theta) point_y = center_circle_y + radius_circle * np.sin(theta) normal_x = np.cos(theta) normal_y = np.sin(theta) grad_x, grad_y = gradient_solution_analytical_problem_c( point_x, point_y) neumann_val = grad_x * normal_x + grad_y * normal_y neumann_control_points_problem_c_dummy.append( NeumannControlPoint(loc=(point_x, point_y), val=neumann_val, normal_vector=(normal_x, normal_y))) # all Neumann control points neumann_control_points_problem_c_all = \ neumann_control_points_problem_c + neumann_control_points_problem_c_dummy cbc_problem_c = CustomBoundaryCondition( center_point=Point(loc=(0.0, 0.0)), dirichlet_control_points=dirichlet_control_points_problem_c_all, neumann_control_points=neumann_control_points_problem_c_all) def get_grid(x_from_to, y_from_to, x_n_points=100, y_n_points=100, as_tensor=False): x_from, x_to = x_from_to y_from, y_to = y_from_to if as_tensor: x = torch.linspace(x_from, x_to, x_n_points) y = torch.linspace(y_from, y_to, y_n_points) return torch.meshgrid(x, y) else: x = np.linspace(x_from, x_to, x_n_points) y = np.linspace(y_from, y_to, y_n_points) return np.meshgrid(x, y) def to_np(tensor): return tensor.detach().numpy() xx_train, yy_train = get_grid(x_from_to=(-1, 1), y_from_to=(-1, 1), x_n_points=28, y_n_points=28, as_tensor=True) is_in_domain_train = cbc_problem_c.in_domain(xx_train, yy_train) xx_train, yy_train = to_np(xx_train), to_np(yy_train) xx_train, yy_train = xx_train[is_in_domain_train], yy_train[ is_in_domain_train] train_gen = PredefinedGenerator(xx_train, yy_train) xx_valid, yy_valid = get_grid(x_from_to=(-1, 1), y_from_to=(-1, 1), x_n_points=10, y_n_points=10, as_tensor=True) is_in_domain_valid = cbc_problem_c.in_domain(xx_valid, yy_valid) xx_valid, yy_valid = to_np(xx_valid), to_np(yy_valid) xx_valid, yy_valid = xx_valid[is_in_domain_valid], yy_valid[ is_in_domain_valid] valid_gen = PredefinedGenerator(xx_valid, yy_valid) def rmse(u, x, y): true_u = torch.log(1 + x**2 + y**2) return torch.mean((u - true_u)**2)**0.5 # nabla^2 psi(x, y) = (e^(-x))(x-2+y^3+6y) def de_problem_c(u, x, y): return diff(u, x, order=2) + diff(u, y, order=2) + torch.exp( u) - 1.0 - x**2 - y**2 - 4.0 / (1.0 + x**2 + y**2)**2 # fully connected network with one hidden layer (100 hidden units with ELU activation) net = FCNN(n_input_units=2, hidden_units=(100, 100), actv=nn.ELU) adam = optim.Adam(params=net.parameters(), lr=0.001) # train on 28 X 28 grid solution_neural_net_problem_c, history_problem_c = solve2D( pde=de_problem_c, condition=cbc_problem_c, xy_min=(-1, -1), xy_max=(1, 1), train_generator=train_gen, valid_generator=valid_gen, net=net, max_epochs=1, batch_size=128, optimizer=adam, monitor=Monitor2D(check_every=1, xy_min=(-1, -1), xy_max=(1, 1), valid_generator=valid_gen), metrics={'rmse': rmse}) xs = torch.tensor([p.loc[0] for p in dirichlet_control_points_problem_c], requires_grad=True).reshape(-1, 1) ys = torch.tensor([p.loc[1] for p in dirichlet_control_points_problem_c], requires_grad=True).reshape(-1, 1) us = solution_neural_net_problem_c(xs, ys, as_type='np') true_us = solution_analytical_problem_c(to_np(xs), to_np(ys)) assert isclose(us, true_us, atol=1e-4).all() xs = torch.tensor([p.loc[0] for p in neumann_control_points_problem_c], requires_grad=True).reshape(-1, 1) ys = torch.tensor([p.loc[1] for p in neumann_control_points_problem_c], requires_grad=True).reshape(-1, 1) us = solution_neural_net_problem_c(xs, ys) nxs = torch.tensor([ p.normal_vector[0] for p in neumann_control_points_problem_c ]).reshape(-1, 1) nys = torch.tensor([ p.normal_vector[1] for p in neumann_control_points_problem_c ]).reshape(-1, 1) normal_derivative = to_np(nxs * diff(us, xs) + nys * diff(us, ys)).flatten() true_normal_derivative = np.array( [p.val for p in neumann_control_points_problem_c]) assert isclose(normal_derivative, true_normal_derivative, atol=1e-2).all()