<commit_before>//! Provides an adaptive sampler which will start sampling at
//! one rate and then take more samples if it determines more
//! are necessary for the pixel. The samples generated are the
//! same as those from the Low Discrepancy sampler but the
//! number of samples taken per pixel will vary.

use std::u32;
use std::f32;
use rand::{Rng, StdRng};
use rand::distributions::{IndependentSample, Range};

use sampler::{Sampler, Region, ld};
use film::ImageSample;

/// Adaptive sampler that makes use of the (0, 2) sequence to generate
/// well distributed samples and takes `min_spp` to `max_spp` samples per pixel
pub struct Adaptive {
    region: Region,
    /// Number of samples to take per pixel
    min_spp: usize,
    max_spp: usize,
    /// How many samples we've taken for this pixel so far
    samples_taken: usize,
    scramble_range: Range<u32>,
}

impl Adaptive {
    /// Create a low discrepancy sampler to sample the image in `dim.0 * dim.1` sized blocks
    pub fn new(dim: (u32, u32), mut min_spp: usize, mut max_spp: usize) -> Adaptive {
        if !min_spp.is_power_of_two() {
            min_spp = min_spp.next_power_of_two();
            print!("Warning: Adaptive sampler requires power of two samples per pixel, ");
            println!("rounding min_spp up to {}", min_spp);
        }
        if !max_spp.is_power_of_two() {
            max_spp = max_spp.next_power_of_two();
            print!("Warning: Adaptive sampler requires power of two samples per pixel, ");
            println!("rounding max_spp up to {}", max_spp);
        }
        Adaptive { region: Region::new((0, 0), dim), min_spp: min_spp, max_spp: max_spp,
                   samples_taken: 0, scramble_range: Range::new(0, u32::MAX) }
    }
    /// Determine if more samples need to be taken for the pixel currently sampled with the
    /// set of samples passed. This is done by simply looking at the contrast difference
    /// between the samples. TODO: What are some better strategies for estimating
    /// if we need more samples?
    fn needs_supersampling(&self, samples: &[ImageSample]) -> bool {
        let max_contrast = 0.5;
        let avg_lum = samples.iter().fold(0.0, |ac, s| ac + s.color.luminance()) / samples.len() as f32;
        for s in samples.iter() {
            if f32::abs(s.color.luminance() - avg_lum) / avg_lum > max_contrast {
                return true;
            }
        }
        return false;
    }
}

impl Sampler for Adaptive {
    fn get_samples(&mut self, samples: &mut Vec<(f32, f32)>, rng: &mut StdRng) {
        samples.clear();
        if !self.has_samples() {
            return;
        }

        self.samples_taken += self.min_spp;
        if samples.len() < self.samples_taken {
            samples.resize(self.samples_taken, (0.0, 0.0));
        }<commit_msg>Fix sample increment in adaptive sampler<commit_after>//! Provides an adaptive sampler which will start sampling at
//! one rate and then take more samples if it determines more
//! are necessary for the pixel. The samples generated are the
//! same as those from the Low Discrepancy sampler but the
//! number of samples taken per pixel will vary.

use std::u32;
use std::f32;
use rand::{Rng, StdRng};
use rand::distributions::{IndependentSample, Range};

use sampler::{Sampler, Region, ld};
use film::ImageSample;

/// Adaptive sampler that makes use of the (0, 2) sequence to generate
/// well distributed samples and takes `min_spp` to `max_spp` samples per pixel
pub struct Adaptive {
    region: Region,
    /// Number of samples to take per pixel
    min_spp: usize,
    max_spp: usize,
    /// How many samples we've taken for this pixel so far
    samples_taken: usize,
    scramble_range: Range<u32>,
}

impl Adaptive {
    /// Create a low discrepancy sampler to sample the image in `dim.0 * dim.1` sized blocks
    pub fn new(dim: (u32, u32), mut min_spp: usize, mut max_spp: usize) -> Adaptive {
        if !min_spp.is_power_of_two() {
            min_spp = min_spp.next_power_of_two();
            print!("Warning: Adaptive sampler requires power of two samples per pixel, ");
            println!("rounding min_spp up to {}", min_spp);
        }
        if !max_spp.is_power_of_two() {
            max_spp = max_spp.next_power_of_two();
            print!("Warning: Adaptive sampler requires power of two samples per pixel, ");
            println!("rounding max_spp up to {}", max_spp);
        }
        Adaptive { region: Region::new((0, 0), dim), min_spp: min_spp, max_spp: max_spp,
                   samples_taken: 0, scramble_range: Range::new(0, u32::MAX) }
    }
    /// Determine if more samples need to be taken for the pixel currently sampled with the
    /// set of samples passed. This is done by simply looking at the contrast difference
    /// between the samples. TODO: What are some better strategies for estimating
    /// if we need more samples?
    fn needs_supersampling(&self, samples: &[ImageSample]) -> bool {
        let max_contrast = 0.5;
        let avg_lum = samples.iter().fold(0.0, |ac, s| ac + s.color.luminance()) / samples.len() as f32;
        for s in samples.iter() {
            if f32::abs(s.color.luminance() - avg_lum) / avg_lum > max_contrast {
                return true;
            }
        }
        return false;
    }
}

impl Sampler for Adaptive {
    fn get_samples(&mut self, samples: &mut Vec<(f32, f32)>, rng: &mut StdRng) {
        samples.clear();
        if !self.has_samples() {
            return;
        }

        self.samples_taken += self.min_spp;
        if samples.len() < self.min_spp {
            samples.resize(self.min_spp, (0.0, 0.0));
        }
{'fraction_non_alphanumeric': 0.11065936008485062, 'fraction_numerical': 0.012727594131164928, 'mean_word_length': 2.599236641221374, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5751488', 'n_tokens_mistral': 1836, 'n_tokens_neox': 1757, 'n_words': 605}