Skip to content

Commit

Permalink
Wrapped up distr_2d.h refactoring and fixed testcases
Browse files Browse the repository at this point in the history
  • Loading branch information
wjakob committed Feb 16, 2020
1 parent ce523e9 commit e56afd5
Show file tree
Hide file tree
Showing 14 changed files with 605 additions and 479 deletions.
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
[submodule "ext/pugixml"]
path = ext/pugixml
url = https://github.com/mitsuba-renderer/pugixml
[submodule "ext/zeromq"]
path = ext/zeromq
url = https://github.com/mitsuba-renderer/zeromq
[submodule "ext/asmjit"]
path = ext/asmjit
url = https://github.com/mitsuba-renderer/asmjit
Expand Down
2 changes: 1 addition & 1 deletion ext/nanogui
1 change: 0 additions & 1 deletion ext/zeromq
Submodule zeromq deleted from d7c3a6
4 changes: 2 additions & 2 deletions include/mitsuba/core/distr_1d.h
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ template <typename Float> struct ContinuousDistribution {

Float y0 = gather<Float>(m_pdf, index, active),
y1 = gather<Float>(m_pdf, index + 1u, active),
c0 = gather<Float>(m_cdf, index- 1u, active && index > 0);
c0 = gather<Float>(m_cdf, index - 1u, active && index > 0);

value = (value - c0) * m_inv_interval_size;

Expand Down Expand Up @@ -487,7 +487,7 @@ template <typename Float> struct ContinuousDistribution {

Float y0 = gather<Float>(m_pdf, index, active),
y1 = gather<Float>(m_pdf, index + 1u, active),
c0 = gather<Float>(m_cdf, index- 1u, active && index > 0);
c0 = gather<Float>(m_cdf, index - 1u, active && index > 0);

value = (value - c0) * m_inv_interval_size;

Expand Down
606 changes: 311 additions & 295 deletions include/mitsuba/core/distr_2d.h

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
[tool:pytest]
minversion = 3.0
norecursedirs = ext ext_build build build-debug CMakeFiles dist include
norecursedirs = ext ext_build build build-debug CMakeFiles dist include .git
python_paths = dist dist/python


[pycodestyle]
# E402 module level import not at top of file
# E402 module level import not at top of file (needed for Mitsuba variants)
ignore = E402
28 changes: 14 additions & 14 deletions src/bsdfs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
set(MTS_PLUGIN_PREFIX "bsdfs")

add_plugin(blendbsdf blendbsdf.cpp)
add_plugin(conductor conductor.cpp)
add_plugin(dielectric dielectric.cpp)
add_plugin(diffuse diffuse.cpp)
add_plugin(mask mask.cpp)
add_plugin(measured measured.cpp)
add_plugin(null null.cpp)
add_plugin(plastic plastic.cpp)
add_plugin(roughconductor roughconductor.cpp)
add_plugin(blendbsdf blendbsdf.cpp)
add_plugin(conductor conductor.cpp)
add_plugin(dielectric dielectric.cpp)
add_plugin(diffuse diffuse.cpp)
add_plugin(mask mask.cpp)
add_plugin(measured measured.cpp)
add_plugin(null null.cpp)
add_plugin(plastic plastic.cpp)
add_plugin(roughconductor roughconductor.cpp)
add_plugin(roughdielectric roughdielectric.cpp)
add_plugin(roughplastic roughplastic.cpp)
add_plugin(thindielectric thindielectric.cpp)
add_plugin(twosided twosided.cpp)
add_plugin(polarizer polarizer.cpp)
add_plugin(retarder retarder.cpp)
add_plugin(roughplastic roughplastic.cpp)
add_plugin(thindielectric thindielectric.cpp)
add_plugin(twosided twosided.cpp)
add_plugin(polarizer polarizer.cpp)
add_plugin(retarder retarder.cpp)

# Register the test directory
add_tests(${CMAKE_CURRENT_SOURCE_DIR}/tests)
11 changes: 5 additions & 6 deletions src/bsdfs/tests/test_diffuse.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,16 @@ def test02_eval_pdf(variant_scalar):

def test03_chi2(variant_packet):
from mitsuba.python.chi2 import BSDFAdapter, ChiSquareTest, SphericalDomain
from mitsuba.core import ScalarBoundingBox2f

sample_func, pdf_func = BSDFAdapter("diffuse", '')

chi2 = ChiSquareTest(
domain = SphericalDomain(),
sample_func = sample_func,
pdf_func = pdf_func,
sample_dim = 3
domain=SphericalDomain(),
sample_func=sample_func,
pdf_func=pdf_func,
sample_dim=3
)

result = chi2.run(0.1)
# chi2._dump_tables()
assert result
assert result
78 changes: 78 additions & 0 deletions src/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# This file rewrites exceptions caught by PyTest and makes traces involving
# pybind11 classes more readable. It e.g. replaces "<built-in method allclose
# of PyCapsule object at 0x7ffa78041090>" by "allclose" which is arguably just
# as informative and much more compact.

import pytest
import re

re1 = re.compile(r'<built-in method (\w*) of PyCapsule object at 0x[0-9a-f]*>')
re2 = re.compile(r'<bound method PyCapsule.(\w*)[^>]*>')


def patch_line(s):
s = re1.sub(r'\1', s)
s = re2.sub(r'\1', s)
return s


def patch_tb(tb): # tb: ReprTraceback
for entry in tb.reprentries:
entry.lines = [patch_line(l) for l in entry.lines]


@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
rep = outcome.get_result()
if rep.outcome == 'failed':
for entry in rep.longrepr.chain:
patch_tb(entry[0])
return rep


def generate_fixture(variant):
@pytest.fixture(scope='module')
def fixture():
try:
import mitsuba
mitsuba.set_variant(variant)
except Exception:
pytest.skip('Mitsuba variant "%s" is not enabled!' % variant)
globals()['variant_' + variant] = fixture


for variant in ['scalar_rgb', 'scalar_spectral',
'scalar_mono_polarized', 'packet_rgb']:
generate_fixture(variant)
del generate_fixture


@pytest.fixture(params=['packet_rgb', 'gpu_rgb'])
def variants_vec_rgb(request):
try:
import mitsuba
mitsuba.set_variant(request.param)
except Exception:
pytest.skip('Mitsuba variant "%s" is not enabled!' % request.param)
return request.param


@pytest.fixture(params=['scalar_rgb', 'packet_rgb'])
def variants_cpu_rgb(request):
try:
import mitsuba
mitsuba.set_variant(request.param)
except Exception:
pytest.skip('Mitsuba variant "%s" is not enabled!' % request.param)
return request.param


@pytest.fixture(params=['scalar_rgb', 'packet_rgb', 'gpu_rgb'])
def variants_all_rgb(request):
try:
import mitsuba
mitsuba.set_variant(request.param)
except Exception:
pytest.skip('Mitsuba variant "%s" is not enabled!' % request.param)
return request.param
2 changes: 1 addition & 1 deletion src/libcore/python/distr_2d_v.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ template <typename Warp> auto bind_warp(py::module &m,
if constexpr (Warp::Dimension == 0)
warp.def(std::move(constructor), "data"_a,
"param_values"_a = py::list(), "normalize"_a = true,
"build_hierarchy"_a = true, doc_constructor);
"enable_sampling"_a = true, doc_constructor);
else
warp.def(std::move(constructor), "data"_a, "param_values"_a,
"normalize"_a = true, "build_hierarchy"_a = true,
Expand Down
57 changes: 36 additions & 21 deletions src/libcore/tests/test_distr_1d.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import mitsuba
import pytest
import enoki as ek

from mitsuba.python.test import variant_packet


def test01_discr_empty(variant_packet):
def test01_discr_empty(variant_packet_rgb):
# Test that operations involving the empty distribution throw
from mitsuba.core import DiscreteDistribution

d = DiscreteDistribution()
Expand All @@ -16,23 +14,26 @@ def test01_discr_empty(variant_packet):
assert 'empty distribution' in str(excinfo.value)


def test02_discr_zero_prob(variant_packet):
def test02_discr_zero_prob(variant_packet_rgb):
# Test that operations involving zero probability mass throw
from mitsuba.core import DiscreteDistribution

with pytest.raises(RuntimeError) as excinfo:
DiscreteDistribution([0, 0, 0])
assert "no probability mass found" in str(excinfo.value)


def test03_discr_neg_prob(variant_packet):
def test03_discr_neg_prob(variant_packet_rgb):
# Test that operations involving negative probability mass throw
from mitsuba.core import DiscreteDistribution

with pytest.raises(RuntimeError) as excinfo:
DiscreteDistribution([1, -1, 1])
assert "entries must be non-negative" in str(excinfo.value)


def test04_discr_basic(variant_packet):
def test04_discr_basic(variant_packet_rgb):
# Validate discrete distribution cdf/pmf against hand-computed reference
from mitsuba.core import DiscreteDistribution, Float

x = DiscreteDistribution([1, 3, 2])
Expand Down Expand Up @@ -63,7 +64,8 @@ def test04_discr_basic(variant_packet):
assert ek.allclose(x.normalization(), 1.0 / 3.0)


def test05_discr_sample(variant_packet):
def test05_discr_sample(variant_packet_rgb):
# Validate discrete distribution sampling against hand-computed reference
from mitsuba.core import DiscreteDistribution, Float
eps = 1e-7

Expand Down Expand Up @@ -100,7 +102,8 @@ def test05_discr_sample(variant_packet):
)


def test06_discr_bruteforce(variant_packet):
def test06_discr_bruteforce(variant_packet_rgb):
# Brute force validation of discrete distribution sampling
from mitsuba.core import DiscreteDistribution, Float, PCG32, UInt64

rng = PCG32(initseq=UInt64.arange(50))
Expand All @@ -117,18 +120,21 @@ def test06_discr_bruteforce(variant_packet):
z = ek.gather(ddistr.cdf(), y - 1, y > 0)
x *= ddistr.sum()

# Did we sample the right interval?
assert ek.all((x > z) | (ek.eq(x, 0) & (x >= z)))


def test07_discr_leading_trailing_zeros(variant_packet):
def test07_discr_leading_trailing_zeros(variant_packet_rgb):
# Check that sampling still works when there are zero-valued buckets
from mitsuba.core import DiscreteDistribution
x = DiscreteDistribution([0, 0, 1, 0, 1, 0, 0, 0])
index, pmf = x.sample_pmf([-100, 0, 0.5, 0.5 + 1e-6, 1, 100])
assert index == [2, 2, 2, 4, 4, 4]
assert pmf == [.5] * 6


def test08_cont_empty(variant_packet):
def test08_cont_empty(variant_packet_rgb):
# Test that operations involving the empty distribution throw
from mitsuba.core import ContinuousDistribution

d = ContinuousDistribution()
Expand All @@ -144,7 +150,8 @@ def test08_cont_empty(variant_packet):
assert 'needs at least two entries' in str(excinfo.value)


def test09_cont_empty_invalid_range(variant_packet):
def test09_cont_empty_invalid_range(variant_packet_rgb):
# Test that invalid range specifications throw an exception
from mitsuba.core import ContinuousDistribution

with pytest.raises(RuntimeError) as excinfo:
Expand All @@ -156,23 +163,26 @@ def test09_cont_empty_invalid_range(variant_packet):
assert 'invalid range' in str(excinfo.value)


def test10_cont_zero_prob(variant_packet):
def test10_cont_zero_prob(variant_packet_rgb):
# Test that operations involving zero probability mass throw
from mitsuba.core import ContinuousDistribution

with pytest.raises(RuntimeError) as excinfo:
ContinuousDistribution([1, 2], [0, 0, 0])
assert "no probability mass found" in str(excinfo.value)


def test11_cont_neg_prob(variant_packet):
def test11_cont_neg_prob(variant_packet_rgb):
# Test that operations involving negative probability mass throw
from mitsuba.core import ContinuousDistribution

with pytest.raises(RuntimeError) as excinfo:
ContinuousDistribution([1, 2], [1, -1, 1])
assert "entries must be non-negative" in str(excinfo.value)


def test12_cont_eval(variant_packet):
def test12_cont_eval(variant_packet_rgb):
# Test continuous 1D distribution pdf/cdf against hand-computed reference
from mitsuba.core import ContinuousDistribution
d = ContinuousDistribution([2, 3], [1, 2])
eps = 1e-6
Expand All @@ -198,7 +208,8 @@ def test12_cont_eval(variant_packet):
)


def test13_cont_func(variant_packet):
def test13_cont_func(variant_packet_rgb):
# Test continuous 1D distribution integral against analytic result
from mitsuba.core import ContinuousDistribution, Float

x = ek.linspace(Float, -2, 2, 513)
Expand All @@ -210,7 +221,8 @@ def test13_cont_func(variant_packet):
assert ek.allclose(d.sample([0, 0.5, 1]), [-2, 0, 2])


def test14_irrcont_empty(variant_packet):
def test14_irrcont_empty(variant_packet_rgb):
# Test that operations involving the empty distribution throw
from mitsuba.core import IrregularContinuousDistribution

d = IrregularContinuousDistribution()
Expand All @@ -230,7 +242,8 @@ def test14_irrcont_empty(variant_packet):
assert 'size mismatch' in str(excinfo.value)


def test15_irrcont_empty_invalid_range(variant_packet):
def test15_irrcont_empty_invalid_range(variant_packet_rgb):
# Test that invalid range specifications throw an exception
from mitsuba.core import IrregularContinuousDistribution

with pytest.raises(RuntimeError) as excinfo:
Expand All @@ -242,23 +255,25 @@ def test15_irrcont_empty_invalid_range(variant_packet):
assert 'strictly increasing' in str(excinfo.value)


def test16_irrcont_zero_prob(variant_packet):
def test16_irrcont_zero_prob(variant_packet_rgb):
# Test that operations involving the empty distribution throw
from mitsuba.core import IrregularContinuousDistribution

with pytest.raises(RuntimeError) as excinfo:
IrregularContinuousDistribution([1, 2, 3], [0, 0, 0])
assert "no probability mass found" in str(excinfo.value)


def test17_irrcont_neg_prob(variant_packet):
def test17_irrcont_neg_prob(variant_packet_rgb):
# Test that operations involving negative probability mass throw
from mitsuba.core import IrregularContinuousDistribution

with pytest.raises(RuntimeError) as excinfo:
IrregularContinuousDistribution([1, 2, 3], [1, -1, 1])
assert "entries must be non-negative" in str(excinfo.value)


def test18_irrcont_simple_function(variant_packet):
def test18_irrcont_simple_function(variant_packet_rgb):
# Reference from Mathematica
from mitsuba.core import IrregularContinuousDistribution, Float

Expand Down
Loading

0 comments on commit e56afd5

Please sign in to comment.