|
| 1 | +from collections.abc import Callable |
| 2 | + |
1 | 3 | import numpy as np |
2 | 4 | import pytest |
| 5 | +from numpy.typing import NDArray |
| 6 | +from pint import Quantity |
3 | 7 |
|
4 | 8 | import LabIFSC2 as lab |
5 | 9 | from tests.utilities import assert_medida_proxima |
6 | 10 |
|
7 | 11 |
|
8 | | -def test_soma(): |
9 | | - |
10 | | - x, y = lab.Medida(0, "", 0.1), lab.Medida(5, "", 0.3) |
11 | | - |
12 | | - assert (y + 3).nominal("") == 8 |
13 | | - assert (y - 3).nominal("") == 2 |
14 | | - assert (y - 3.13).nominal("") == 5 - 3.13 |
15 | | - |
16 | | - incerteza_esperada = np.hypot(0.1, 0.3) |
17 | | - assert_medida_proxima(x + y, 5, incerteza_esperada) |
18 | | - assert_medida_proxima(y + x, 5, incerteza_esperada) |
19 | | - assert_medida_proxima(x - y, -5, incerteza_esperada) |
20 | | - assert_medida_proxima(y - x, 5, incerteza_esperada) |
21 | | - |
22 | | - assert_medida_proxima(x - x, 0, 0) |
23 | | - assert_medida_proxima(y - y, 0, 0) |
24 | | - z = lab.Medida(5, "", 0.01) * lab.Medida(5, "", 0.01) |
25 | | - w = lab.Medida(5, "", 0.01) |
26 | | - assert np.isclose((z + w).nominal(""), 30, 1e-4) |
27 | | - assert np.isclose((z - w).nominal(""), 20, 1e-4) |
28 | | - |
29 | | - |
30 | | -def test_multiplicacao_medidas(): |
31 | | - x = lab.Medida(0, "", 0.1) |
32 | | - y = lab.Medida(0, "", 0.1) |
33 | | - correlacionado = x * x |
34 | | - nao_correlacionado = lab._medida.montecarlo(lambda a, b: a * b, x, y) |
35 | | - assert not (np.any(correlacionado.histograma) < 0) |
36 | | - assert np.any(nao_correlacionado.histograma > 0) and np.any( |
37 | | - nao_correlacionado.histograma < 0 |
38 | | - ) |
39 | | - assert not ( |
40 | | - correlacionado._histograma is None and nao_correlacionado._histograma is None |
| 12 | +def test_operacoes_com_a_mesma_medida_preservam_correlacao() -> None: |
| 13 | + medida = lab.Medida(5, "", 0.1) |
| 14 | + medida_clone = lab.Medida(5, "", 0.1) |
| 15 | + assert_medida_proxima(medida + medida, 10, 0.2) |
| 16 | + assert_medida_proxima(medida - medida, 0, 0) |
| 17 | + assert_medida_proxima(medida / medida, 1, 0) |
| 18 | + with pytest.raises(AssertionError): |
| 19 | + assert_medida_proxima(medida + medida_clone, 10, 0.2) |
| 20 | + with pytest.raises(AssertionError): |
| 21 | + assert_medida_proxima(medida - medida_clone, 0, 0.0) |
| 22 | + with pytest.raises(AssertionError): |
| 23 | + assert_medida_proxima(medida / medida_clone, 1, 0) |
| 24 | + |
| 25 | + |
| 26 | +@pytest.mark.parametrize( |
| 27 | + ("operacao", "transformacao_no_histograma"), |
| 28 | + [ |
| 29 | + (lambda medida: medida + 3, lambda amostras: amostras + 3), |
| 30 | + (lambda medida: 3 + medida, lambda amostras: 3 + amostras), |
| 31 | + (lambda medida: medida - 3, lambda amostras: amostras - 3), |
| 32 | + (lambda medida: 3 - medida, lambda amostras: 3 - amostras), |
| 33 | + (lambda medida: medida * -3, lambda histograma: histograma * -3), |
| 34 | + (lambda medida: medida / -3, lambda histograma: histograma / -3), |
| 35 | + (lambda medida: -medida, lambda histograma: -histograma), |
| 36 | + (lambda medida: abs(medida), lambda histograma: abs(histograma)), |
| 37 | + (lambda medida: +medida, lambda histograma: histograma), |
| 38 | + ], |
| 39 | +) |
| 40 | +def test_operacoes_exatas_transformam_cada_amostra_do_histograma( |
| 41 | + operacao: Callable[[lab.Medida], lab.Medida], |
| 42 | + transformacao_no_histograma: Callable[[NDArray[np.float64]], NDArray[np.float64]], |
| 43 | +) -> None: |
| 44 | + medida = lab.Medida(-5, "m", 0.1) |
| 45 | + histograma_original = medida.histograma |
| 46 | + assert isinstance(histograma_original, Quantity) |
| 47 | + |
| 48 | + histograma_resultado = operacao(medida).histograma |
| 49 | + assert isinstance(histograma_resultado, Quantity) |
| 50 | + np.testing.assert_allclose( |
| 51 | + histograma_resultado.magnitude, |
| 52 | + transformacao_no_histograma(histograma_original.magnitude), |
41 | 53 | ) |
42 | | - w = lab.Medida(0, "", 0.1) |
43 | | - assert ( |
44 | | - lab.comparar_medidas(w * x, nao_correlacionado) == lab.Comparacao.EQUIVALENTES |
45 | | - ) |
46 | | - |
47 | | - |
48 | | -def test_multiplicacao_cte(): |
49 | | - x = lab.Medida(5, "", 0.1) |
50 | | - y = 3 * x |
51 | | - assert_medida_proxima(y, 15, 0.3) |
52 | | - y = (-3) * x |
53 | | - assert_medida_proxima(y, -15, 0.3) |
54 | | - |
55 | | - y = x * 3 |
56 | | - assert_medida_proxima(y, 15, 0.3) |
57 | | - y = x * (-3) |
58 | | - assert_medida_proxima(y, -15, 0.3) |
59 | | - |
60 | | - |
61 | | -def test_mudanca_de_sinal(): |
62 | | - x = lab.Medida(5, "", 0.1) |
63 | | - y = -x |
64 | | - assert y.nominal("") == -5 and y.incerteza("") == 0.1 |
65 | | - assert x.nominal("") == 5 and x.incerteza("") == 0.1 # cria uma cópia |
66 | | - y = abs(y) |
67 | | - assert y.nominal("") == 5 and y.incerteza("") == 0.1 |
68 | | - w = abs(x / y) |
69 | | - assert np.isclose(w.nominal(""), 1, rtol=1e-3) |
70 | | - |
71 | | - z = +w |
72 | | - for i in range(len(z.histograma)): |
73 | | - assert z.histograma[i] == w.histograma[i] |
74 | | - w._nominal = 3 |
75 | | - assert not isinstance(z._nominal, int) # cria uma cópia |
76 | | - |
77 | 54 |
|
78 | | -def test_divisao(): |
79 | | - x = lab.Medida(-3, "", 0.1) |
80 | | - correlacao = x / x |
81 | | - assert correlacao.nominal("") == 1 and correlacao.incerteza("") == 0 |
82 | 55 |
|
83 | | - x = lab.Medida(5, "", 0.1) |
84 | | - assert (x / 5).nominal("") == 1 and (x / 5).incerteza("") == 0.1 / 5 |
85 | | - |
86 | | - y = lab.Medida(-3, "", 0.1) |
87 | | - assert (x / y).incerteza("") != 0 |
88 | | - |
89 | | - assert np.isclose((10 / x).nominal(""), 2, 1e-3) |
90 | | - |
91 | | - divisao = (y / x).nominal("") |
92 | | - divisao_inversa = (x / y).nominal("") |
93 | | - assert np.isclose(divisao, 1 / divisao_inversa, rtol=1e-2) |
94 | | - |
95 | | - with pytest.raises(TypeError): |
96 | | - "3" / lab.Medida(0, "", 0.1) |
97 | | - |
98 | | - |
99 | | -def test_divisoes_especiais_nao_existe(): |
100 | | - statements = [lambda x, y: x // y, lambda x, y: x % y, lambda x, y: divmod(x, y)] |
101 | | - with pytest.raises(TypeError): |
102 | | - for statement in statements: |
103 | | - statement(lab.Medida(6, "", 0.1), lab.Medida(1, "", 0.1)) |
104 | | - |
105 | | - |
106 | | -def test_potencia(): |
107 | | - x = lab.Medida(2, "", 0.01) |
108 | | - y = lab.Medida(6, "", 0.01) |
109 | | - assert np.isclose((x**3).nominal(""), 8, 1e-3) |
110 | | - assert np.isclose((2**x).nominal(""), 4, 1e-3) |
111 | | - assert np.isclose((x**y).nominal(""), 64, 1e-2) |
112 | | - assert (x**y).incerteza("") > (x**2).incerteza("") |
113 | | - assert np.isclose((x**-20).nominal(""), 1 / (2**20), 1e-3) |
| 56 | +@pytest.mark.parametrize( |
| 57 | + "operacao", |
| 58 | + [ |
| 59 | + lambda medida: "3" / medida, |
| 60 | + lambda medida: medida ** "3", |
| 61 | + lambda medida: "3" ** medida, |
| 62 | + lambda medida: medida // 2, |
| 63 | + lambda medida: medida % 2, |
| 64 | + lambda medida: divmod(medida, 2), |
| 65 | + ], |
| 66 | +) |
| 67 | +def test_operacoes_nao_suportadas_levantam_type_error( |
| 68 | + operacao: Callable[[lab.Medida], object], |
| 69 | +) -> None: |
114 | 70 | with pytest.raises(TypeError): |
115 | | - lab.Medida(0, "", 0.1) ** "3" |
116 | | - with pytest.raises(TypeError): |
117 | | - "3" ** lab.Medida(0, "", 0.1) |
118 | | - |
119 | | - |
120 | | -def test_soma_subtracao_constante_histograma(): |
121 | | - x = lab.Medida(5, "m", 0.1) |
122 | | - h_x = x.histograma |
123 | | - |
124 | | - y = x + 3.0 |
125 | | - h_y = y.histograma |
126 | | - |
127 | | - z = x - 2.0 |
128 | | - h_z = z.histograma |
129 | | - |
130 | | - assert np.allclose(h_y.magnitude - h_x.magnitude, 3.0) |
131 | | - assert np.allclose(h_z.magnitude - h_x.magnitude, -2.0) |
| 71 | + operacao(lab.Medida(6, "", 0.1)) |
| 72 | + |
| 73 | + |
| 74 | +OperacaoVetorizada = Callable[[lab.Medida, NDArray[np.object_]], NDArray[np.object_]] |
| 75 | +OperacaoEscalar = Callable[[lab.Medida, lab.Medida], lab.Medida] |
| 76 | + |
| 77 | + |
| 78 | +@pytest.mark.parametrize( |
| 79 | + ("operacao_vetorizada", "operacao_elemento"), |
| 80 | + [ |
| 81 | + (lambda escalar, array: escalar + array, lambda escalar, item: escalar + item), |
| 82 | + (lambda escalar, array: array + escalar, lambda escalar, item: item + escalar), |
| 83 | + (lambda escalar, array: escalar - array, lambda escalar, item: escalar - item), |
| 84 | + (lambda escalar, array: array - escalar, lambda escalar, item: item - escalar), |
| 85 | + (lambda escalar, array: escalar * array, lambda escalar, item: escalar * item), |
| 86 | + (lambda escalar, array: array * escalar, lambda escalar, item: item * escalar), |
| 87 | + (lambda escalar, array: escalar / array, lambda escalar, item: escalar / item), |
| 88 | + (lambda escalar, array: array / escalar, lambda escalar, item: item / escalar), |
| 89 | + (lambda escalar, array: escalar**array, lambda escalar, item: escalar**item), |
| 90 | + (lambda escalar, array: array**escalar, lambda escalar, item: item**escalar), |
| 91 | + ], |
| 92 | +) |
| 93 | +def test_operacoes_entre_medida_e_array_sao_elemento_a_elemento( |
| 94 | + operacao_vetorizada: OperacaoVetorizada, |
| 95 | + operacao_elemento: OperacaoEscalar, |
| 96 | +) -> None: |
| 97 | + escalar = lab.Medida(2, "", 0.01) |
| 98 | + medidas = lab.arrayM([1, 2, 4], "", 0.02) |
| 99 | + |
| 100 | + resultado = operacao_vetorizada(escalar, medidas) |
| 101 | + |
| 102 | + assert isinstance(resultado, np.ndarray) |
| 103 | + assert resultado.shape == medidas.shape |
| 104 | + assert resultado.dtype == object |
| 105 | + for obtido, item in zip(resultado, medidas, strict=True): |
| 106 | + assert isinstance(obtido, lab.Medida) |
| 107 | + esperado = operacao_elemento(escalar, item) |
| 108 | + assert_medida_proxima( |
| 109 | + obtido, |
| 110 | + esperado.nominal(""), |
| 111 | + esperado.incerteza(""), |
| 112 | + rtol=1e-3, |
| 113 | + atol=1e-6, |
| 114 | + ) |
0 commit comments