Split some more things out into sub-crates.
Also translated the Halton generator to rust and made it a crate where the code is generated by a build.rs file.
This commit is contained in:
parent
96db00b10a
commit
b698a52f6c
40
Cargo.lock
generated
40
Cargo.lock
generated
|
@ -1,20 +1,6 @@
|
||||||
[root]
|
[root]
|
||||||
name = "psychopath"
|
name = "spectra_xyz"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
|
||||||
"clap 2.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"lodepng 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"mem_arena 0.1.0",
|
|
||||||
"nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"openexr 0.1.0 (git+https://github.com/cessen/openexr-rs?rev=612fc6c81c031970ffddcab15509236711613de8)",
|
|
||||||
"rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi_term"
|
name = "ansi_term"
|
||||||
|
@ -74,6 +60,10 @@ name = "gcc"
|
||||||
version = "0.3.45"
|
version = "0.3.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "halton"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kernel32-sys"
|
name = "kernel32-sys"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -145,6 +135,26 @@ name = "pkg-config"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "psychopath"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap 2.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"halton 0.1.0",
|
||||||
|
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lodepng 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"mem_arena 0.1.0",
|
||||||
|
"nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num_cpus 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"openexr 0.1.0 (git+https://github.com/cessen/openexr-rs?rev=612fc6c81c031970ffddcab15509236711613de8)",
|
||||||
|
"rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"simd 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"spectra_xyz 0.1.0",
|
||||||
|
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.1.17"
|
version = "0.1.17"
|
||||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -1,5 +1,5 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = ["mem_arena"]
|
members = ["sub_crates/mem_arena", "sub_crates/halton", "sub_crates/spectra_xyz"]
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "psychopath"
|
name = "psychopath"
|
||||||
|
@ -29,5 +29,11 @@ simd = { version = "0.2.0", optional = true }
|
||||||
openexr = { git = "https://github.com/cessen/openexr-rs", rev = "612fc6c81c031970ffddcab15509236711613de8" }
|
openexr = { git = "https://github.com/cessen/openexr-rs", rev = "612fc6c81c031970ffddcab15509236711613de8" }
|
||||||
|
|
||||||
# Local crate dependencies
|
# Local crate dependencies
|
||||||
|
[dependencies.halton]
|
||||||
|
path = "sub_crates/halton"
|
||||||
|
|
||||||
[dependencies.mem_arena]
|
[dependencies.mem_arena]
|
||||||
path = "mem_arena"
|
path = "sub_crates/mem_arena"
|
||||||
|
|
||||||
|
[dependencies.spectra_xyz]
|
||||||
|
path = "sub_crates/spectra_xyz"
|
|
@ -3,11 +3,12 @@
|
||||||
use std;
|
use std;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
use halton;
|
||||||
|
|
||||||
use algorithm::{partition, quick_select};
|
use algorithm::{partition, quick_select};
|
||||||
use bbox::BBox;
|
use bbox::BBox;
|
||||||
use lerp::lerp_slice;
|
use lerp::lerp_slice;
|
||||||
use math::{Vector, dot};
|
use math::{Vector, dot};
|
||||||
use sampling::halton;
|
|
||||||
use sampling::uniform_sample_hemisphere;
|
use sampling::uniform_sample_hemisphere;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
mod spectra_xyz;
|
|
||||||
|
|
||||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Div, DivAssign};
|
use std::ops::{Add, AddAssign, Mul, MulAssign, Div, DivAssign};
|
||||||
|
|
||||||
|
use spectra_xyz::{spectrum_xyz_to_p, EQUAL_ENERGY_REFLECTANCE};
|
||||||
|
|
||||||
use float4::Float4;
|
use float4::Float4;
|
||||||
use lerp::Lerp;
|
use lerp::Lerp;
|
||||||
use math::faster_exp;
|
use math::faster_exp;
|
||||||
|
|
||||||
use self::spectra_xyz::{spectrum_xyz_to_p, EQUAL_ENERGY_REFLECTANCE};
|
|
||||||
|
|
||||||
|
|
||||||
// Minimum and maximum wavelength of light we care about, in nanometers
|
// Minimum and maximum wavelength of light we care about, in nanometers
|
||||||
const WL_MIN: f32 = 380.0;
|
const WL_MIN: f32 = 380.0;
|
|
@ -1,4 +1,6 @@
|
||||||
|
extern crate halton;
|
||||||
extern crate mem_arena;
|
extern crate mem_arena;
|
||||||
|
extern crate spectra_xyz;
|
||||||
|
|
||||||
extern crate crossbeam;
|
extern crate crossbeam;
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
|
|
|
@ -8,6 +8,8 @@ use std::sync::{RwLock, Mutex};
|
||||||
use crossbeam::sync::MsQueue;
|
use crossbeam::sync::MsQueue;
|
||||||
use scoped_threadpool::Pool;
|
use scoped_threadpool::Pool;
|
||||||
|
|
||||||
|
use halton;
|
||||||
|
|
||||||
use algorithm::partition_pair;
|
use algorithm::partition_pair;
|
||||||
use accel::ACCEL_TRAV_TIME;
|
use accel::ACCEL_TRAV_TIME;
|
||||||
use color::{Color, XYZ, SpectralSample, map_0_1_to_wavelength};
|
use color::{Color, XYZ, SpectralSample, map_0_1_to_wavelength};
|
||||||
|
@ -17,7 +19,6 @@ use hilbert;
|
||||||
use image::Image;
|
use image::Image;
|
||||||
use math::{fast_logit, upper_power_of_two};
|
use math::{fast_logit, upper_power_of_two};
|
||||||
use ray::Ray;
|
use ray::Ray;
|
||||||
use sampling::halton;
|
|
||||||
use scene::Scene;
|
use scene::Scene;
|
||||||
use surface;
|
use surface;
|
||||||
use timer::Timer;
|
use timer::Timer;
|
||||||
|
@ -158,6 +159,7 @@ impl<'a> Renderer<'a> {
|
||||||
halton::sample(1, offset + si as u32)),
|
halton::sample(1, offset + si as u32)),
|
||||||
halton::sample(2, offset + si as u32),
|
halton::sample(2, offset + si as u32),
|
||||||
map_0_1_to_wavelength(halton::sample(3,
|
map_0_1_to_wavelength(halton::sample(3,
|
||||||
|
|
||||||
offset +
|
offset +
|
||||||
si as
|
si as
|
||||||
u32)),
|
u32)),
|
||||||
|
|
|
@ -1,186 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Copyright (c) 2012 Leonhard Gruenschloss (leonhard@gruenschloss.org)
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
|
||||||
# in the Software without restriction, including without limitation the rights to
|
|
||||||
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
# of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
# so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in
|
|
||||||
# all copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
# SOFTWARE.
|
|
||||||
|
|
||||||
# Adapted to generate Rust instead of C by Nathan Vegdahl
|
|
||||||
# Generate Rust code for evaluating Halton points with Faure-permutations for different bases.
|
|
||||||
|
|
||||||
# How many components to generate.
|
|
||||||
num_dimensions = 128
|
|
||||||
|
|
||||||
# Check primality. Not optimized, since it's not performance-critical.
|
|
||||||
def is_prime(p):
|
|
||||||
for i in range(2, p):
|
|
||||||
if not p % i:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Init prime number array.
|
|
||||||
primes = []
|
|
||||||
candidate = 1
|
|
||||||
for i in range(num_dimensions):
|
|
||||||
while (True):
|
|
||||||
candidate += 1
|
|
||||||
if (is_prime(candidate)):
|
|
||||||
break;
|
|
||||||
primes.append(candidate)
|
|
||||||
|
|
||||||
# Compute the Faure digit permutation for 0, ..., b - 1.
|
|
||||||
def get_faure_permutation(b):
|
|
||||||
if b < 2:
|
|
||||||
return (0,)
|
|
||||||
|
|
||||||
elif b == 2:
|
|
||||||
return (0, 1)
|
|
||||||
|
|
||||||
elif b & 1: # odd
|
|
||||||
c = (b - 1) / 2
|
|
||||||
|
|
||||||
def faure_odd(i):
|
|
||||||
if i == c:
|
|
||||||
return c
|
|
||||||
|
|
||||||
f = faure[b - 1][i - int(i > c)]
|
|
||||||
return f + int(f >= c)
|
|
||||||
|
|
||||||
return tuple((faure_odd(i) for i in range(b)))
|
|
||||||
|
|
||||||
else: # even
|
|
||||||
c = b / 2
|
|
||||||
|
|
||||||
def faure_even(i):
|
|
||||||
if i < c:
|
|
||||||
return 2 * faure[c][i]
|
|
||||||
else:
|
|
||||||
return 2 * faure[c][i - c] + 1
|
|
||||||
|
|
||||||
return tuple((faure_even(i) for i in range(b)))
|
|
||||||
|
|
||||||
# Init Faure permutations.
|
|
||||||
faure = []
|
|
||||||
for b in range(primes[-1] + 1):
|
|
||||||
faure.append(get_faure_permutation(b))
|
|
||||||
|
|
||||||
# Compute the radical inverse with Faure permutations.
|
|
||||||
def invert(base, index, digits):
|
|
||||||
result = 0
|
|
||||||
for i in range(digits):
|
|
||||||
index, remainder = divmod(index, base)
|
|
||||||
result = result * base + faure[base][remainder]
|
|
||||||
return result
|
|
||||||
|
|
||||||
# Print the beginning bits of the file
|
|
||||||
print '''#![allow(dead_code)]
|
|
||||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
|
||||||
// Copyright (c) 2012 Leonhard Gruenschloss (leonhard@gruenschloss.org)
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights to
|
|
||||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
// of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
// so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
// This file is automatically generated.
|
|
||||||
|
|
||||||
// Compute points of the Halton sequence with with Faure-permutations for different bases.
|
|
||||||
|
|
||||||
pub const MAX_DIMENSION: u32 = %d;''' % num_dimensions
|
|
||||||
|
|
||||||
# Print the sampling function
|
|
||||||
print '''
|
|
||||||
pub fn sample(dimension: u32, index: u32) -> f32 {
|
|
||||||
match dimension {'''
|
|
||||||
|
|
||||||
for i in range(num_dimensions):
|
|
||||||
print ' %d => halton%d(index),' % (i, primes[i])
|
|
||||||
|
|
||||||
print '''
|
|
||||||
_ => panic!("Exceeded max dimensions."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
|
|
||||||
# Print the special-cased first dimension
|
|
||||||
print '''
|
|
||||||
// Special case: radical inverse in base 2, with direct bit reversal.
|
|
||||||
fn halton2(mut index: u32) -> f32 {
|
|
||||||
index = (index << 16) | (index >> 16);
|
|
||||||
index = ((index & 0x00ff00ff) << 8) | ((index & 0xff00ff00) >> 8);
|
|
||||||
index = ((index & 0x0f0f0f0f) << 4) | ((index & 0xf0f0f0f0) >> 4);
|
|
||||||
index = ((index & 0x33333333) << 2) | ((index & 0xcccccccc) >> 2);
|
|
||||||
index = ((index & 0x55555555) << 1) | ((index & 0xaaaaaaaa) >> 1);
|
|
||||||
return (index as f32) * (1.0 / ((1u64 << 32) as f32));
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
|
|
||||||
for i in range(1, num_dimensions): # Skip base 2.
|
|
||||||
base = primes[i]
|
|
||||||
|
|
||||||
# Based on the permutation table size, we process multiple digits at once.
|
|
||||||
digits = 1
|
|
||||||
pow_base = base
|
|
||||||
while pow_base * base <= 500: # Maximum permutation table size.
|
|
||||||
pow_base *= base
|
|
||||||
digits += 1
|
|
||||||
|
|
||||||
max_power = pow_base
|
|
||||||
powers = []
|
|
||||||
while max_power * pow_base < (1 << 32): # 32-bit unsigned precision
|
|
||||||
powers.append(max_power)
|
|
||||||
max_power *= pow_base
|
|
||||||
|
|
||||||
# Build the permutation table.
|
|
||||||
perm = []
|
|
||||||
for j in range(pow_base):
|
|
||||||
perm.append(invert(base, j, digits))
|
|
||||||
|
|
||||||
power = max_power / pow_base
|
|
||||||
print '''
|
|
||||||
fn halton%d(index: u32) -> f32 {
|
|
||||||
const PERM%d: [u16; %d] = [%s];
|
|
||||||
''' % (base, base, len(perm), ', '.join(str(k) for k in perm))
|
|
||||||
|
|
||||||
print ''' return (unsafe{*PERM%d.get_unchecked((index %% %d) as usize)} as u32 * %d +''' % \
|
|
||||||
(base, pow_base, power)
|
|
||||||
|
|
||||||
# Advance to next set of digits.
|
|
||||||
div = 1
|
|
||||||
while power / pow_base > 1:
|
|
||||||
div *= pow_base
|
|
||||||
power /= pow_base
|
|
||||||
print ' unsafe{*PERM%d.get_unchecked(((index / %d) %% %d) as usize)} as u32 * %d +' % (base, div, pow_base, power)
|
|
||||||
|
|
||||||
print ''' unsafe{*PERM%d.get_unchecked(((index / %d) %% %d) as usize)} as u32) as f32 * (0.999999940395355224609375f32 / (%du32 as f32)); // Results in [0,1).
|
|
||||||
}
|
|
||||||
''' % (base, div * pow_base, pow_base, max_power)
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,3 @@
|
||||||
pub mod halton;
|
|
||||||
mod monte_carlo;
|
mod monte_carlo;
|
||||||
|
|
||||||
pub use self::monte_carlo::{square_to_circle, cosine_sample_hemisphere, uniform_sample_hemisphere,
|
pub use self::monte_carlo::{square_to_circle, cosine_sample_hemisphere, uniform_sample_hemisphere,
|
||||||
|
|
10
sub_crates/halton/Cargo.toml
Normal file
10
sub_crates/halton/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "halton"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Nathan Vegdahl <cessen@cessen.com>"]
|
||||||
|
license = "MIT"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "halton"
|
||||||
|
path = "src/lib.rs"
|
272
sub_crates/halton/build.rs
Normal file
272
sub_crates/halton/build.rs
Normal file
|
@ -0,0 +1,272 @@
|
||||||
|
// Copyright (c) 2012 Leonhard Gruenschloss (leonhard@gruenschloss.org)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights to
|
||||||
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
// so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
//
|
||||||
|
// Adapted to Rust and to generate Rust instead of C by Nathan Vegdahl
|
||||||
|
|
||||||
|
// Generate Rust code for evaluating Halton points with Faure-permutations for different bases.
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
|
||||||
|
/// How many components to generate.
|
||||||
|
const NUM_DIMENSIONS: usize = 128;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let out_dir = env::var("OUT_DIR").unwrap();
|
||||||
|
let dest_path = Path::new(&out_dir).join("halton.rs");
|
||||||
|
let mut f = File::create(&dest_path).unwrap();
|
||||||
|
|
||||||
|
// Init prime number array.
|
||||||
|
let primes = {
|
||||||
|
let mut primes = Vec::new();
|
||||||
|
let mut candidate = 1;
|
||||||
|
for _ in 0..NUM_DIMENSIONS {
|
||||||
|
loop {
|
||||||
|
candidate += 1;
|
||||||
|
if is_prime(candidate) {
|
||||||
|
primes.push(candidate);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
primes
|
||||||
|
};
|
||||||
|
|
||||||
|
// Init Faure permutations.
|
||||||
|
let faure = {
|
||||||
|
let mut faure: Vec<Vec<usize>> = Vec::new();
|
||||||
|
for b in 0..(primes.last().unwrap() + 1) {
|
||||||
|
let perm = get_faure_permutation(&faure, b);
|
||||||
|
faure.push(perm);
|
||||||
|
}
|
||||||
|
faure
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write the beginning bits of the file
|
||||||
|
f.write_all(format!(r#"
|
||||||
|
// Copyright (c) 2012 Leonhard Gruenschloss (leonhard@gruenschloss.org)
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights to
|
||||||
|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
// of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
// so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
// This file is automatically generated.
|
||||||
|
|
||||||
|
// Compute points of the Halton sequence with with Faure-permutations for different bases.
|
||||||
|
|
||||||
|
pub const MAX_DIMENSION: u32 = {};
|
||||||
|
"#,
|
||||||
|
NUM_DIMENSIONS)
|
||||||
|
.as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Write the sampling function
|
||||||
|
f.write_all(format!(r#"
|
||||||
|
#[inline]
|
||||||
|
pub fn sample(dimension: u32, index: u32) -> f32 {{
|
||||||
|
match dimension {{"#)
|
||||||
|
.as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
for i in 0..NUM_DIMENSIONS {
|
||||||
|
f.write_all(format!(r#"
|
||||||
|
{} => halton{}(index),"#,
|
||||||
|
i,
|
||||||
|
primes[i])
|
||||||
|
.as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
f.write_all(format!(r#"
|
||||||
|
_ => panic!("Exceeded max dimensions."),
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
"#)
|
||||||
|
.as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
// Write the special-cased first dimension
|
||||||
|
f.write_all(format!(r#"
|
||||||
|
// Special case: radical inverse in base 2, with direct bit reversal.
|
||||||
|
fn halton2(mut index: u32) -> f32 {{
|
||||||
|
index = (index << 16) | (index >> 16);
|
||||||
|
index = ((index & 0x00ff00ff) << 8) | ((index & 0xff00ff00) >> 8);
|
||||||
|
index = ((index & 0x0f0f0f0f) << 4) | ((index & 0xf0f0f0f0) >> 4);
|
||||||
|
index = ((index & 0x33333333) << 2) | ((index & 0xcccccccc) >> 2);
|
||||||
|
index = ((index & 0x55555555) << 1) | ((index & 0xaaaaaaaa) >> 1);
|
||||||
|
return (index as f32) * (1.0 / ((1u64 << 32) as f32));
|
||||||
|
}}
|
||||||
|
"#)
|
||||||
|
.as_bytes())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
for i in 1..NUM_DIMENSIONS {
|
||||||
|
// Skip base 2.
|
||||||
|
let base = primes[i];
|
||||||
|
|
||||||
|
// Based on the permutation table size, we process multiple digits at once.
|
||||||
|
let mut digits = 1;
|
||||||
|
let mut pow_base = base;
|
||||||
|
while pow_base * base <= 500 {
|
||||||
|
// Maximum permutation table size.
|
||||||
|
pow_base *= base;
|
||||||
|
digits += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut max_power = pow_base;
|
||||||
|
let mut powers = Vec::new();
|
||||||
|
while (max_power * pow_base) < (1 << 32) {
|
||||||
|
// 32-bit unsigned precision
|
||||||
|
powers.push(max_power);
|
||||||
|
max_power *= pow_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the permutation table.
|
||||||
|
let perm = (0..pow_base).map(|j| invert(&faure, base, j, digits)).collect::<Vec<_>>();
|
||||||
|
let perm_string = {
|
||||||
|
let mut perm_string = String::new();
|
||||||
|
for i in perm.iter() {
|
||||||
|
let s = format!("{}, ", i);
|
||||||
|
perm_string.push_str(&s);
|
||||||
|
}
|
||||||
|
perm_string
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut power = max_power / pow_base;
|
||||||
|
f.write_all(format!(r#"
|
||||||
|
fn halton{}(index: u32) -> f32 {{
|
||||||
|
const PERM{}: [u16; {}] = [{}];"#,
|
||||||
|
base,
|
||||||
|
base,
|
||||||
|
perm.len(),
|
||||||
|
perm_string)
|
||||||
|
.as_bytes())
|
||||||
|
.unwrap();;
|
||||||
|
|
||||||
|
f.write_all(format!(r#"
|
||||||
|
return (unsafe{{*PERM{}.get_unchecked((index % {}) as usize)}} as u32 * {} +"#,
|
||||||
|
base,
|
||||||
|
pow_base,
|
||||||
|
power)
|
||||||
|
.as_bytes())
|
||||||
|
.unwrap();;
|
||||||
|
|
||||||
|
// Advance to next set of digits.
|
||||||
|
let mut div = 1;
|
||||||
|
while power / pow_base > 1 {
|
||||||
|
div *= pow_base;
|
||||||
|
power /= pow_base;
|
||||||
|
f.write_all(format!(r#"
|
||||||
|
unsafe{{*PERM{}.get_unchecked(((index / {}) % {}) as usize)}} as u32 * {} +"#,
|
||||||
|
base,
|
||||||
|
div,
|
||||||
|
pow_base,
|
||||||
|
power)
|
||||||
|
.as_bytes())
|
||||||
|
.unwrap();;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.write_all(format!(r#"
|
||||||
|
unsafe{{*PERM{}.get_unchecked(((index / {}) % {}) as usize)}} as u32) as f32 *
|
||||||
|
(0.999999940395355224609375f32 / ({}u32 as f32)); // Results in [0,1).
|
||||||
|
}}
|
||||||
|
"#,
|
||||||
|
base,
|
||||||
|
div * pow_base,
|
||||||
|
pow_base,
|
||||||
|
max_power)
|
||||||
|
.as_bytes())
|
||||||
|
.unwrap();;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Check primality. Not optimized, since it's not performance-critical.
|
||||||
|
fn is_prime(p: usize) -> bool {
|
||||||
|
for i in 2..p {
|
||||||
|
if (p % i) == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Computes the Faure digit permutation for 0, ..., b - 1.
|
||||||
|
fn get_faure_permutation(faure: &Vec<Vec<usize>>, b: usize) -> Vec<usize> {
|
||||||
|
if b < 2 {
|
||||||
|
return vec![0];
|
||||||
|
} else if b == 2 {
|
||||||
|
return vec![0, 1];
|
||||||
|
} else if (b & 1) != 0 {
|
||||||
|
// odd
|
||||||
|
let c = (b - 1) / 2;
|
||||||
|
|
||||||
|
return (0..b)
|
||||||
|
.map(|i| {
|
||||||
|
if i == c {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
let f: usize = faure[b - 1][i - ((i > c) as usize)];
|
||||||
|
f + ((f >= c) as usize)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
} else {
|
||||||
|
// even
|
||||||
|
let c = b / 2;
|
||||||
|
|
||||||
|
return (0..b)
|
||||||
|
.map(|i| if i < c {
|
||||||
|
2 * faure[c][i]
|
||||||
|
} else {
|
||||||
|
2 * faure[c][i - c] + 1
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the radical inverse with Faure permutations.
|
||||||
|
fn invert(faure: &Vec<Vec<usize>>, base: usize, mut index: usize, digits: usize) -> usize {
|
||||||
|
let mut result = 0;
|
||||||
|
for _ in 0..digits {
|
||||||
|
let remainder = index % base;
|
||||||
|
index = index / base;
|
||||||
|
result = result * base + faure[base][remainder];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
4
sub_crates/halton/src/lib.rs
Normal file
4
sub_crates/halton/src/lib.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
// Include the file generated by the build.rs script
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/halton.rs"));
|
9
sub_crates/spectra_xyz/Cargo.toml
Normal file
9
sub_crates/spectra_xyz/Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "spectra_xyz"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Nathan Vegdahl <cessen@cessen.com>"]
|
||||||
|
license = "MIT"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "spectra_xyz"
|
||||||
|
path = "src/lib.rs"
|
Loading…
Reference in New Issue
Block a user