181 lines
4.9 KiB
Python
181 lines
4.9 KiB
Python
import torch
|
|
import random
|
|
import pytest
|
|
from pina.model import SplineSurface
|
|
from pina import LabelTensor
|
|
|
|
|
|
# Utility quantities for testing
|
|
orders = [random.randint(1, 8) for _ in range(2)]
|
|
n_ctrl_pts = random.randint(max(orders), max(orders) + 5)
|
|
n_knots = [orders[i] + n_ctrl_pts for i in range(2)]
|
|
|
|
# Input tensor
|
|
points = [
|
|
LabelTensor(torch.rand(100, 2), ["x", "y"]),
|
|
LabelTensor(torch.rand(2, 100, 2), ["x", "y"]),
|
|
]
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"knots_u",
|
|
[
|
|
torch.rand(n_knots[0]),
|
|
{"n": n_knots[0], "min": 0, "max": 1, "mode": "auto"},
|
|
{"n": n_knots[0], "min": 0, "max": 1, "mode": "uniform"},
|
|
None,
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"knots_v",
|
|
[
|
|
torch.rand(n_knots[1]),
|
|
{"n": n_knots[1], "min": 0, "max": 1, "mode": "auto"},
|
|
{"n": n_knots[1], "min": 0, "max": 1, "mode": "uniform"},
|
|
None,
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"control_points", [torch.rand(n_ctrl_pts, n_ctrl_pts), None]
|
|
)
|
|
def test_constructor(knots_u, knots_v, control_points):
|
|
|
|
# Skip if knots_u, knots_v, and control_points are all None
|
|
if (knots_u is None or knots_v is None) and control_points is None:
|
|
return
|
|
|
|
SplineSurface(
|
|
orders=orders,
|
|
knots_u=knots_u,
|
|
knots_v=knots_v,
|
|
control_points=control_points,
|
|
)
|
|
|
|
# Should fail if orders is not list of two elements
|
|
with pytest.raises(ValueError):
|
|
SplineSurface(
|
|
orders=[orders[0]],
|
|
knots_u=knots_u,
|
|
knots_v=knots_v,
|
|
control_points=control_points,
|
|
)
|
|
|
|
# Should fail if both knots and control_points are None
|
|
with pytest.raises(ValueError):
|
|
SplineSurface(
|
|
orders=orders,
|
|
knots_u=None,
|
|
knots_v=None,
|
|
control_points=None,
|
|
)
|
|
|
|
# Should fail if control_points is not a torch.Tensor when provided
|
|
with pytest.raises(ValueError):
|
|
SplineSurface(
|
|
orders=orders,
|
|
knots_u=knots_u,
|
|
knots_v=knots_v,
|
|
control_points=[[0.0] * n_ctrl_pts] * n_ctrl_pts,
|
|
)
|
|
|
|
# Should fail if control_points is not of the correct shape when provided
|
|
# It assumes that at least one among knots_u and knots_v is not None
|
|
if knots_u is not None or knots_v is not None:
|
|
with pytest.raises(ValueError):
|
|
SplineSurface(
|
|
orders=orders,
|
|
knots_u=knots_u,
|
|
knots_v=knots_v,
|
|
control_points=torch.rand(n_ctrl_pts + 1, n_ctrl_pts + 1),
|
|
)
|
|
|
|
# Should fail if there are not enough knots_u to define the control points
|
|
with pytest.raises(ValueError):
|
|
SplineSurface(
|
|
orders=orders,
|
|
knots_u=torch.linspace(0, 1, orders[0]),
|
|
knots_v=knots_v,
|
|
control_points=None,
|
|
)
|
|
|
|
# Should fail if there are not enough knots_v to define the control points
|
|
with pytest.raises(ValueError):
|
|
SplineSurface(
|
|
orders=orders,
|
|
knots_u=knots_u,
|
|
knots_v=torch.linspace(0, 1, orders[1]),
|
|
control_points=None,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"knots_u",
|
|
[
|
|
torch.rand(n_knots[0]),
|
|
{"n": n_knots[0], "min": 0, "max": 1, "mode": "auto"},
|
|
{"n": n_knots[0], "min": 0, "max": 1, "mode": "uniform"},
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"knots_v",
|
|
[
|
|
torch.rand(n_knots[1]),
|
|
{"n": n_knots[1], "min": 0, "max": 1, "mode": "auto"},
|
|
{"n": n_knots[1], "min": 0, "max": 1, "mode": "uniform"},
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"control_points", [torch.rand(n_ctrl_pts, n_ctrl_pts), None]
|
|
)
|
|
@pytest.mark.parametrize("pts", points)
|
|
def test_forward(knots_u, knots_v, control_points, pts):
|
|
|
|
# Define the model
|
|
model = SplineSurface(
|
|
orders=orders,
|
|
knots_u=knots_u,
|
|
knots_v=knots_v,
|
|
control_points=control_points,
|
|
)
|
|
|
|
# Evaluate the model
|
|
output_ = model(pts)
|
|
assert output_.shape == (*pts.shape[:-1], 1)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"knots_u",
|
|
[
|
|
torch.rand(n_knots[0]),
|
|
{"n": n_knots[0], "min": 0, "max": 1, "mode": "auto"},
|
|
{"n": n_knots[0], "min": 0, "max": 1, "mode": "uniform"},
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"knots_v",
|
|
[
|
|
torch.rand(n_knots[1]),
|
|
{"n": n_knots[1], "min": 0, "max": 1, "mode": "auto"},
|
|
{"n": n_knots[1], "min": 0, "max": 1, "mode": "uniform"},
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"control_points", [torch.rand(n_ctrl_pts, n_ctrl_pts), None]
|
|
)
|
|
@pytest.mark.parametrize("pts", points)
|
|
def test_backward(knots_u, knots_v, control_points, pts):
|
|
|
|
# Define the model
|
|
model = SplineSurface(
|
|
orders=orders,
|
|
knots_u=knots_u,
|
|
knots_v=knots_v,
|
|
control_points=control_points,
|
|
)
|
|
|
|
# Evaluate the model
|
|
output_ = model(pts)
|
|
loss = torch.mean(output_)
|
|
loss.backward()
|
|
assert model.control_points.grad.shape == model.control_points.shape
|