<commit_before>#[macro_use]
extern crate log;
extern crate xswag_base as base;
extern crate lalrpop_util;

pub mod lex;
pub mod ast;
pub mod grammar;

use base::diag::{Remark, Report, Snippet};
use base::code::{BytePos, FileMap, Span};
use lalrpop_util::ParseError;
use lex::{Token, TokenSpan};
use std::cell::RefCell;

const MAX_PREVIEW_LEN: usize = 15;

pub fn parse_compilation_unit(file: &FileMap)
    -> (Option<ast::CompilationUnit>, Vec<Report>)
{
    // Save all tokens that have been read already
    let tokens = RefCell::new(Vec::new());
    let lexing_err = RefCell::new(None);

    // Stop at the first lexing error and remove all non real token for parsing
    let lexer = lex::Tokenizer::new(file)
        .take_while(|res| match res {
            &Ok(_) => true,
            &Err(ref e) => {
                *lexing_err.borrow_mut() = Some(e.clone());
                false
            }
        })
        .map(Result::unwrap)
        .inspect(|t| tokens.borrow_mut().push(t.clone()))
        .map(|ts| { (ts.span.lo, ts.tok, ts.span.hi) })
        .filter(|t| t.1.is_real());

    let mut errors = Vec::new();

    let res = grammar::java8::parse_CompilationUnit(&mut errors, lexer);
    let res = res.map_err(|e| match e {
        ParseError::User { error: e } => e,
        ParseError::InvalidToken { location: loc } => {
            Report::simple_error("lalrpop InvalidToken", Span::single(loc))
        },
        ParseError::UnrecognizedToken { token, expected } => {
            match token {
                None => {
                    Report::simple_spanless_error(
                        "Unexpected end of file (EOF) while parsing. Maybe you \
                            forgot to close a parentheses or brace?",
                    )
                },
                Some((lo, tok, hi)) => {
                    handle_unexpected_token(
                        tok,
                        Span::new(lo, hi),
                        file,
                        &expected,
                        &tokens.borrow(),
                    )
                }
            }
        },
        ParseError::ExtraToken  { token: (lo, tok, hi) } => {
            Report::simple_error(
                format!("lalrpop ExtraToken {:?}", tok),
                Span::new(lo, hi),
            )
        },
    });

    let mut reps = Vec::new();
    let ast = if let Some(ref lexing_err) = *lexing_err.borrow() {
        reps.push(lexing_err.report.clone());
        None
    } else {
        res.map(|ast| Some(ast)).unwrap_or_else(|e| { reps.push(e); None })
    };

    reps.extend_from_slice(&errors);
    (ast, reps)
}

fn handle_unexpected_token(
    token: Token,
    span: Span,
    file: &FileMap,
    expected: &[String],
    tokens: &[TokenSpan]
) -> Report {
    // ------ Prepare a nice error message -------
    let tok_name = token.as_java_string();

    // Prepare token preview
    let mut chs = file.src()[span.into_range()].chars();
    let mut tok_str: String = chs.by_ref().take(MAX_PREVIEW_LEN).collect();
    if chs.next().is_some() {
        // if the original span was longer than 15 chars, we append '...'
        tok_str.push_str("...");
    }

    // pack as `Report`
    let msg = if tok_name == tok_str {
        format!(
            "unexpected '{}'. Expected one of {:?}",
            tok_name,
            expected,
        )
    } else {
        format!(
            "unexpected token '{}' (`{}`). Expected one of {:?}",
            tok_name,
            tok_str,
            expected,
        )
    };
    let rep = Report::simple_error(msg, span);

    // ------ Check if we can give the user some more useful information ------
    // Check if the user has forgotten a semicolon. We trigger this note if
    //   1. the unexpected token is the first token in the line
    //   2. the last line does not end with a semicolon or a opening brace '{'
    //

    // The `loc_lo` was returned from the map: unwrap OK
    let loc_lo = file.get_loc(span.lo);
    let line = file.get_line(loc_lo.line).unwrap();

    // check condition [1]
    let is_line_start = line
        .char_indices()
        .take_while(|&(i, _)| i < loc_lo.col.0 as usize)
        .all(|(_, c)| c.is_whitespace());

    // check condition [2]
    let prev = tokens
        .iter()
        .rev()
        // get the previous token (ignoring whitespace)
        .skip_while(|ts| ts.span.lo >= span.lo)
        .find(|ts| ts.tok.is_real());
    let is_good = prev.map(|ts| ts.tok == Token::Semi || ts.tok == Token::BraceOp);

    if is_line_start && is_good == Some(false) {
        // we can safely unwrap here: `is_good.is_some()` => `prev.is_some()`
        rep.with_remark(Remark::note(
            "maybe you forgot a semicolon (`;`) at the end of this line?",
            Snippet::Replace {
                span: Span::empty_at(prev.unwrap().span.hi),
                with: ";".into(),
            },
        ))
    } else {
        rep.with_note("this is a syntax error. Make sure all \
            parentheses are balanced and nothing is missing.")
    }
}
<commit_msg>Add check name of public type == filename<commit_after>#[macro_use]
extern crate log;
extern crate xswag_base as base;
extern crate lalrpop_util;

pub mod lex;
pub mod ast;
pub mod grammar;

use base::diag::{Remark, Report, Snippet};
use base::code::{BytePos, FileMap, Span};
use lalrpop_util::ParseError;
use lex::{Token, TokenSpan};
use std::cell::RefCell;
use ast::ItemExt;

const MAX_PREVIEW_LEN: usize = 15;

pub fn parse_compilation_unit(file: &FileMap)
    -> (Option<ast::CompilationUnit>, Vec<Report>)
{
    // Save all tokens that have been read already
    let tokens = RefCell::new(Vec::new());
    let lexing_err = RefCell::new(None);

    // Stop at the first lexing error and remove all non real token for parsing
    let lexer = lex::Tokenizer::new(file)
        .take_while(|res| match res {
            &Ok(_) => true,
            &Err(ref e) => {
                *lexing_err.borrow_mut() = Some(e.clone());
                false
            }
        })
        .map(Result::unwrap)
        .inspect(|t| tokens.borrow_mut().push(t.clone()))
        .map(|ts| { (ts.span.lo, ts.tok, ts.span.hi) })
        .filter(|t| t.1.is_real());

    let mut errors = Vec::new();

    let res = grammar::java8::parse_CompilationUnit(&mut errors, lexer);
    let res = res.map_err(|e| match e {
        ParseError::User { error: e } => e,
        ParseError::InvalidToken { location: loc } => {
            Report::simple_error("lalrpop InvalidToken", Span::single(loc))
        },
        ParseError::UnrecognizedToken { token, expected } => {
            match token {
                None => {
                    Report::simple_spanless_error(
                        "Unexpected end of file (EOF) while parsing. Maybe you \
                            forgot to close a parentheses or brace?",
                    )
                },
                Some((lo, tok, hi)) => {
                    handle_unexpected_token(
                        tok,
                        Span::new(lo, hi),
                        file,
                        &expected,
                        &tokens.borrow(),
                    )
                }
            }
        },
        ParseError::ExtraToken  { token: (lo, tok, hi) } => {
            Report::simple_error(
                format!("lalrpop ExtraToken {:?}", tok),
                Span::new(lo, hi),
            )
        },
    });

    let mut reps = Vec::new();
    let ast = if let Some(ref lexing_err) = *lexing_err.borrow() {
        reps.push(lexing_err.report.clone());
        None
    } else {
        res.map(|ast| Some(ast)).unwrap_or_else(|e| { reps.push(e); None })
    };

    if let Some(ref ast) = ast {
        let fname = file.filename()
            .trim_right_matches(".java")
            .trim_right_matches(".jav");
        let wrong_types = ast.types
            .iter()
            .filter(|ty| ty.vis() == ast::Visibility::Public)
            .filter_map(|ty| ty.ident())
            .filter(|&ident| ident.name != fname);
        for &ast::Ident { ref name, span } in wrong_types {
            let msg = format!(
                "a public type called '{}' should be declared in a file \
                    called '{}.java'. Either rename your file appropriately \
                    or rename the type to '{}'",
                name,
                name,
                fname
            );
            reps.push(Report::simple_error(msg, span));
        }
    }

    reps.extend_from_slice(&errors);
    (ast, reps)
}

fn handle_unexpected_token(
    token: Token,
    span: Span,
    file: &FileMap,
    expected: &[String],
    tokens: &[TokenSpan]
) -> Report {
    // ------ Prepare a nice error message -------
    let tok_name = token.as_java_string();

    // Prepare token preview
    let mut chs = file.src()[span.into_range()].chars();
    let mut tok_str: String = chs.by_ref().take(MAX_PREVIEW_LEN).collect();
    if chs.next().is_some() {
        // if the original span was longer than 15 chars, we append '...'
        tok_str.push_str("...");
    }

    // pack as `Report`
    let msg = if tok_name == tok_str {
        format!(
            "unexpected '{}'. Expected one of {:?}",
            tok_name,
            expected,
        )
    } else {
        format!(
            "unexpected token '{}' (`{}`). Expected one of {:?}",
            tok_name,
            tok_str,
            expected,
        )
    };
    let rep = Report::simple_error(msg, span);

    // ------ Check if we can give the user some more useful information ------
    // Check if the user has forgotten a semicolon. We trigger this note if
    //   1. the unexpected token is the first token in the line
    //   2. the last line does not end with a semicolon or a opening brace '{'
    //

    // The `loc_lo` was returned from the map: unwrap OK
    let loc_lo = file.get_loc(span.lo);
    let line = file.get_line(loc_lo.line).unwrap();

    // check condition [1]
    let is_line_start = line
        .char_indices()
        .take_while(|&(i, _)| i < loc_lo.col.0 as usize)
        .all(|(_, c)| c.is_whitespace());

    // check condition [2]
    let prev = tokens
        .iter()
        .rev()
        // get the previous token (ignoring whitespace)
        .skip_while(|ts| ts.span.lo >= span.lo)
        .find(|ts| ts.tok.is_real());
    let is_good = prev.map(|ts| ts.tok == Token::Semi || ts.tok == Token::BraceOp);

    if is_line_start && is_good == Some(false) {
        // we can safely unwrap here: `is_good.is_some()` => `prev.is_some()`
        rep.with_remark(Remark::note(
            "maybe you forgot a semicolon (`;`) at the end of this line?",
            Snippet::Replace {
                span: Span::empty_at(prev.unwrap().span.hi),
                with: ";".into(),
            },
        ))
    } else {
        rep.with_note("this is a syntax error. Make sure all \
            parentheses are balanced and nothing is missing.")
    }
}
<|endoftext|>


<commit_before>//! A small GPU compute shader demonstration.
//!
//! Here we use a compute shader to calculate the amplitude of `OSCILLATOR_COUNT` number of
//! oscillators. The oscillator amplitudes are then laid out across the screen using rectangles
//! with a gray value equal to the amplitude. Real-time interaction is demonstrated by providing
//! access to time, frequency (mouse `x`) and the number of oscillators via uniform data.

use nannou::prelude::*;
use std::sync::{Arc, Mutex};

struct Model {
    compute: Compute,
    oscillators: Arc<Mutex<Vec<f32>>>,
}

struct Compute {
    oscillator_buffer: wgpu::Buffer,
    oscillator_buffer_size: wgpu::BufferAddress,
    uniform_buffer: wgpu::Buffer,
    bind_group: wgpu::BindGroup,
    pipeline: wgpu::ComputePipeline,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct Uniforms {
    time: f32,
    freq: f32,
    oscillator_count: u32,
}

const OSCILLATOR_COUNT: u32 = 128;

fn main() {
    nannou::app(model).update(update).run();
}

fn model(app: &App) -> Model {
    let w_id = app.new_window()
        .size(1440, 512)
        .view(view)
        .build()
        .unwrap();
    let window = app.window(w_id).unwrap();
    let device = window.swap_chain_device();

    // Create the compute shader module.
    let cs = include_bytes!("shaders/comp.spv");
    let cs_spirv = wgpu::read_spirv(std::io::Cursor::new(&cs[..])).unwrap();
    let cs_mod = device.create_shader_module(&cs_spirv);

    // Create the buffer that will store the result of our compute operation.
    let oscillator_buffer_size = (OSCILLATOR_COUNT as usize * std::mem::size_of::<f32>()) as wgpu::BufferAddress;
    let oscillator_buffer = device.create_buffer(&wgpu::BufferDescriptor {
        size: oscillator_buffer_size,
        usage: wgpu::BufferUsage::STORAGE
            | wgpu::BufferUsage::COPY_DST
            | wgpu::BufferUsage::COPY_SRC,
    });

    // Create the buffer that will store time.
    let uniforms = create_uniforms(app.time, app.mouse.x, window.rect());
    let uniform_buffer = device
        .create_buffer_mapped(1, wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST)
        .fill_from_slice(&[uniforms]);

    // Create the bind group and pipeline.
    let bind_group_layout = create_bind_group_layout(device);
    let bind_group = create_bind_group(device, &bind_group_layout, &oscillator_buffer, oscillator_buffer_size, &uniform_buffer);
    let pipeline_layout = create_pipeline_layout(device, &bind_group_layout);
    let pipeline = create_compute_pipeline(device, &pipeline_layout, &cs_mod);

    let compute = Compute {
        oscillator_buffer,
        oscillator_buffer_size,
        uniform_buffer,
        bind_group,
        pipeline,
    };

    // The vector that we will write oscillator values to.
    let oscillators = Arc::new(Mutex::new(vec![0.0; OSCILLATOR_COUNT as usize]));

    Model { compute, oscillators }
}

fn update(app: &App, model: &mut Model, _update: Update) {
    let window = app.main_window();
    let device = window.swap_chain_device();
    let win_rect = window.rect();
    let compute = &mut model.compute;

    // The buffer into which we'll read some data.
    let read_buffer = device.create_buffer(&wgpu::BufferDescriptor {
        size: compute.oscillator_buffer_size,
        usage: wgpu::BufferUsage::MAP_READ
            | wgpu::BufferUsage::COPY_DST
            | wgpu::BufferUsage::COPY_SRC,
    });

    // An update for the uniform buffer with the current time.
    let uniforms = create_uniforms(app.time, app.mouse.x, win_rect);
    let uniforms_size = std::mem::size_of::<Uniforms>() as wgpu::BufferAddress;
    let new_uniform_buffer = device
        .create_buffer_mapped(1, wgpu::BufferUsage::COPY_SRC)
        .fill_from_slice(&[uniforms]);

    // The encoder we'll use to encode the compute pass.
    let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
    encoder.copy_buffer_to_buffer(&new_uniform_buffer, 0, &compute.uniform_buffer, 0, uniforms_size);
    {
        let mut cpass = encoder.begin_compute_pass();
        cpass.set_pipeline(&compute.pipeline);
        cpass.set_bind_group(0, &compute.bind_group, &[]);
        cpass.dispatch(OSCILLATOR_COUNT as u32, 1, 1);
    }
    encoder.copy_buffer_to_buffer(&compute.oscillator_buffer, 0, &read_buffer, 0, compute.oscillator_buffer_size);

    // Submit the compute pass to the device's queue.
    window.swap_chain_queue().lock().unwrap().submit(&[encoder.finish()]);

    // Register a callback for reading the result of the compute pass.
    let oscillators = model.oscillators.clone();
    read_buffer.map_read_async(0, compute.oscillator_buffer_size, move |result: wgpu::BufferMapAsyncResult<&[f32]>| {
        if let Ok(mapping) = result {
            if let Ok(mut oscillators) = oscillators.lock() {
                oscillators.copy_from_slice(&mapping.data);
            }
        }
    });

    // Check for resource cleanups and mapping callbacks.
    device.poll(false);
}

fn view(app: &App, model: &Model, frame: &Frame) {
    frame.clear(BLACK);
    let draw = app.draw();
    let window = app.window(frame.window_id()).unwrap();
    let rect = window.rect();

    if let Ok(oscillators) = model.oscillators.lock() {
        let w = rect.w() / OSCILLATOR_COUNT as f32;
        let h = rect.h();
        let half_w = w * 0.5;
        for (i, &osc) in oscillators.iter().enumerate() {
            let x = half_w + map_range(i as u32, 0, OSCILLATOR_COUNT, rect.left(), rect.right());
            draw.rect().w_h(w, h).x(x).color(gray(osc));
        }
    }

    draw.to_frame(app, frame).unwrap();
}

fn create_uniforms(time: f32, mouse_x: f32, win_rect: geom::Rect) -> Uniforms {
    let freq = map_range(mouse_x, win_rect.left(), win_rect.right(), 0.0, win_rect.w());
    let oscillator_count = OSCILLATOR_COUNT;
    Uniforms { time, freq, oscillator_count }
}

fn create_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
    let oscillator_buffer_binding = wgpu::BindGroupLayoutBinding {
        binding: 0,
        visibility: wgpu::ShaderStage::COMPUTE,
        ty: wgpu::BindingType::StorageBuffer { dynamic: false, readonly: false },
    };
    let uniforms_binding = wgpu::BindGroupLayoutBinding {
        binding: 1,
        visibility: wgpu::ShaderStage::COMPUTE,
        ty: wgpu::BindingType::UniformBuffer { dynamic: false },
    };
    device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
        bindings: &[oscillator_buffer_binding, uniforms_binding],
    })
}

fn create_bind_group(
    device: &wgpu::Device,
    layout: &wgpu::BindGroupLayout,
    oscillator_buffer: &wgpu::Buffer,
    oscillator_buffer_size: wgpu::BufferAddress,
    uniform_buffer: &wgpu::Buffer,
) -> wgpu::BindGroup {
    let oscillator_buffer_binding = wgpu::Binding {
        binding: 0,
        resource: wgpu::BindingResource::Buffer {
            buffer: &oscillator_buffer,
            range: 0..oscillator_buffer_size,
        },
    };
    let uniforms_binding = wgpu::Binding {
        binding: 1,
        resource: wgpu::BindingResource::Buffer {
            buffer: &uniform_buffer,
            range: 0..std::mem::size_of::<Uniforms>() as wgpu::BufferAddress,
        },
    };
    let bindings = &[oscillator_buffer_binding, uniforms_binding];
    device.create_bind_group(&wgpu::BindGroupDescriptor { layout, bindings })
}

fn create_pipeline_layout(
    device: &wgpu::Device,
    bind_group_layout: &wgpu::BindGroupLayout,
) -> wgpu::PipelineLayout {
    device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
        bind_group_layouts: &[&bind_group_layout],
    })
}

fn create_compute_pipeline(
    device: &wgpu::Device,
    layout: &wgpu::PipelineLayout,
    cs_mod: &wgpu::ShaderModule,
) -> wgpu::ComputePipeline {
    let compute_stage = wgpu::ProgrammableStageDescriptor {
        module: &cs_mod,
        entry_point: "main",
    };
    let desc = wgpu::ComputePipelineDescriptor { layout, compute_stage };
    device.create_compute_pipeline(&desc)
}
<commit_msg>Fix formatting of the wgpu_compute_shader example<commit_after>//! A small GPU compute shader demonstration.
//!
//! Here we use a compute shader to calculate the amplitude of `OSCILLATOR_COUNT` number of
//! oscillators. The oscillator amplitudes are then laid out across the screen using rectangles
//! with a gray value equal to the amplitude. Real-time interaction is demonstrated by providing
//! access to time, frequency (mouse `x`) and the number of oscillators via uniform data.

use nannou::prelude::*;
use std::sync::{Arc, Mutex};

struct Model {
    compute: Compute,
    oscillators: Arc<Mutex<Vec<f32>>>,
}

struct Compute {
    oscillator_buffer: wgpu::Buffer,
    oscillator_buffer_size: wgpu::BufferAddress,
    uniform_buffer: wgpu::Buffer,
    bind_group: wgpu::BindGroup,
    pipeline: wgpu::ComputePipeline,
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct Uniforms {
    time: f32,
    freq: f32,
    oscillator_count: u32,
}

const OSCILLATOR_COUNT: u32 = 128;

fn main() {
    nannou::app(model).update(update).run();
}

fn model(app: &App) -> Model {
    let w_id = app.new_window().size(1440, 512).view(view).build().unwrap();
    let window = app.window(w_id).unwrap();
    let device = window.swap_chain_device();

    // Create the compute shader module.
    let cs = include_bytes!("shaders/comp.spv");
    let cs_spirv = wgpu::read_spirv(std::io::Cursor::new(&cs[..])).unwrap();
    let cs_mod = device.create_shader_module(&cs_spirv);

    // Create the buffer that will store the result of our compute operation.
    let oscillator_buffer_size =
        (OSCILLATOR_COUNT as usize * std::mem::size_of::<f32>()) as wgpu::BufferAddress;
    let oscillator_buffer = device.create_buffer(&wgpu::BufferDescriptor {
        size: oscillator_buffer_size,
        usage: wgpu::BufferUsage::STORAGE
            | wgpu::BufferUsage::COPY_DST
            | wgpu::BufferUsage::COPY_SRC,
    });

    // Create the buffer that will store time.
    let uniforms = create_uniforms(app.time, app.mouse.x, window.rect());
    let uniform_buffer = device
        .create_buffer_mapped(1, wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST)
        .fill_from_slice(&[uniforms]);

    // Create the bind group and pipeline.
    let bind_group_layout = create_bind_group_layout(device);
    let bind_group = create_bind_group(
        device,
        &bind_group_layout,
        &oscillator_buffer,
        oscillator_buffer_size,
        &uniform_buffer,
    );
    let pipeline_layout = create_pipeline_layout(device, &bind_group_layout);
    let pipeline = create_compute_pipeline(device, &pipeline_layout, &cs_mod);

    let compute = Compute {
        oscillator_buffer,
        oscillator_buffer_size,
        uniform_buffer,
        bind_group,
        pipeline,
    };

    // The vector that we will write oscillator values to.
    let oscillators = Arc::new(Mutex::new(vec![0.0; OSCILLATOR_COUNT as usize]));

    Model {
        compute,
        oscillators,
    }
}

fn update(app: &App, model: &mut Model, _update: Update) {
    let window = app.main_window();
    let device = window.swap_chain_device();
    let win_rect = window.rect();
    let compute = &mut model.compute;

    // The buffer into which we'll read some data.
    let read_buffer = device.create_buffer(&wgpu::BufferDescriptor {
        size: compute.oscillator_buffer_size,
        usage: wgpu::BufferUsage::MAP_READ
            | wgpu::BufferUsage::COPY_DST
            | wgpu::BufferUsage::COPY_SRC,
    });

    // An update for the uniform buffer with the current time.
    let uniforms = create_uniforms(app.time, app.mouse.x, win_rect);
    let uniforms_size = std::mem::size_of::<Uniforms>() as wgpu::BufferAddress;
    let new_uniform_buffer = device
        .create_buffer_mapped(1, wgpu::BufferUsage::COPY_SRC)
        .fill_from_slice(&[uniforms]);

    // The encoder we'll use to encode the compute pass.
    let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
    encoder.copy_buffer_to_buffer(
        &new_uniform_buffer,
        0,
        &compute.uniform_buffer,
        0,
        uniforms_size,
    );
    {
        let mut cpass = encoder.begin_compute_pass();
        cpass.set_pipeline(&compute.pipeline);
        cpass.set_bind_group(0, &compute.bind_group, &[]);
        cpass.dispatch(OSCILLATOR_COUNT as u32, 1, 1);
    }
    encoder.copy_buffer_to_buffer(
        &compute.oscillator_buffer,
        0,
        &read_buffer,
        0,
        compute.oscillator_buffer_size,
    );

    // Submit the compute pass to the device's queue.
    window
        .swap_chain_queue()
        .lock()
        .unwrap()
        .submit(&[encoder.finish()]);

    // Register a callback for reading the result of the compute pass.
    let oscillators = model.oscillators.clone();
    read_buffer.map_read_async(
        0,
        compute.oscillator_buffer_size,
        move |result: wgpu::BufferMapAsyncResult<&[f32]>| {
            if let Ok(mapping) = result {
                if let Ok(mut oscillators) = oscillators.lock() {
                    oscillators.copy_from_slice(&mapping.data);
                }
            }
        },
    );

    // Check for resource cleanups and mapping callbacks.
    device.poll(false);
}

fn view(app: &App, model: &Model, frame: &Frame) {
    frame.clear(BLACK);
    let draw = app.draw();
    let window = app.window(frame.window_id()).unwrap();
    let rect = window.rect();

    if let Ok(oscillators) = model.oscillators.lock() {
        let w = rect.w() / OSCILLATOR_COUNT as f32;
        let h = rect.h();
        let half_w = w * 0.5;
        for (i, &osc) in oscillators.iter().enumerate() {
            let x = half_w + map_range(i as u32, 0, OSCILLATOR_COUNT, rect.left(), rect.right());
            draw.rect().w_h(w, h).x(x).color(gray(osc));
        }
    }

    draw.to_frame(app, frame).unwrap();
}

fn create_uniforms(time: f32, mouse_x: f32, win_rect: geom::Rect) -> Uniforms {
    let freq = map_range(
        mouse_x,
        win_rect.left(),
        win_rect.right(),
        0.0,
        win_rect.w(),
    );
    let oscillator_count = OSCILLATOR_COUNT;
    Uniforms {
        time,
        freq,
        oscillator_count,
    }
}

fn create_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
    let oscillator_buffer_binding = wgpu::BindGroupLayoutBinding {
        binding: 0,
        visibility: wgpu::ShaderStage::COMPUTE,
        ty: wgpu::BindingType::StorageBuffer {
            dynamic: false,
            readonly: false,
        },
    };
    let uniforms_binding = wgpu::BindGroupLayoutBinding {
        binding: 1,
        visibility: wgpu::ShaderStage::COMPUTE,
        ty: wgpu::BindingType::UniformBuffer { dynamic: false },
    };
    device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
        bindings: &[oscillator_buffer_binding, uniforms_binding],
    })
}

fn create_bind_group(
    device: &wgpu::Device,
    layout: &wgpu::BindGroupLayout,
    oscillator_buffer: &wgpu::Buffer,
    oscillator_buffer_size: wgpu::BufferAddress,
    uniform_buffer: &wgpu::Buffer,
) -> wgpu::BindGroup {
    let oscillator_buffer_binding = wgpu::Binding {
        binding: 0,
        resource: wgpu::BindingResource::Buffer {
            buffer: &oscillator_buffer,
            range: 0..oscillator_buffer_size,
        },
    };
    let uniforms_binding = wgpu::Binding {
        binding: 1,
        resource: wgpu::BindingResource::Buffer {
            buffer: &uniform_buffer,
            range: 0..std::mem::size_of::<Uniforms>() as wgpu::BufferAddress,
        },
    };
    let bindings = &[oscillator_buffer_binding, uniforms_binding];
    device.create_bind_group(&wgpu::BindGroupDescriptor { layout, bindings })
}

fn create_pipeline_layout(
    device: &wgpu::Device,
    bind_group_layout: &wgpu::BindGroupLayout,
) -> wgpu::PipelineLayout {
    device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
        bind_group_layouts: &[&bind_group_layout],
    })
}

fn create_compute_pipeline(
    device: &wgpu::Device,
    layout: &wgpu::PipelineLayout,
    cs_mod: &wgpu::ShaderModule,
) -> wgpu::ComputePipeline {
    let compute_stage = wgpu::ProgrammableStageDescriptor {
        module: &cs_mod,
        entry_point: "main",
    };
    let desc = wgpu::ComputePipelineDescriptor {
        layout,
        compute_stage,
    };
    device.create_compute_pipeline(&desc)
}
<|endoftext|>


<commit_before>use std::thread;
use std::time::Duration;

fn main() {
    simulated_expensive_calculation(2);
}

fn simulated_expensive_calculation(intensity: i32) -> i32 {
    println!("Very expensive calculation...");
    thread::sleep(Duration::from_secs(2));
    intensity
}<commit_msg>Implement generate workout function<commit_after>use std::thread;
use std::time::Duration;

fn main() {
    let simulated_user_specified_value = 3;
    let simulated_random_number = 4;

    generate_workout(simulated_user_specified_value, simulated_random_number);
}

fn simulated_expensive_calculation(intensity: i32) -> i32 {
    println!("Very expensive calculation...");
    thread::sleep(Duration::from_secs(2));
    intensity
}

fn generate_workout(intensity: i32, random_number: i32) {
    if intensity < 25 {
        println!("Do {} pushups!", simulated_expensive_calculation(intensity));
        println!("Next, do {} situps!", simulated_expensive_calculation(intensity));
    } else {
        if random_number == 3 {
            println!("Take a break!");
        } else {
            println!("Run for {} minutes!", simulated_expensive_calculation(intensity));
        }
    }
}<|endoftext|>


<commit_before>extern crate num;

#[macro_use]
mod macros;
pub mod traitdefs;

mod nbez;
pub use nbez::*;

use traitdefs::Float;
use std::marker::PhantomData;

// There are macros in place to make it easier to create new bezier structs, as they can be created
// with a very consistent pattern. However, those macros are also written in a very consistent pattern
// which unfortunately is significantly harder, if not impossible, to create with a traditional
// macro. So, the macro invocations are generated with the build script and then inserted here.
include!(concat!(env!("OUT_DIR"), "/macro_invocs.rs"));

impl<F: Float> Vector2d<F> {
    pub fn perp(self) -> Vector2d<F> {
        Vector2d {
            x: -self.y,
            y: self.x
        }
    }
}

pub struct BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {
    points: *const B::Point,
    len: usize,
    lifetime: PhantomData<&'a ()>
}

impl<'a, F, B> Iterator for BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {
    type Item = B;
    fn next(&mut self) -> Option<B> {
        use std::slice;

        let order = B::order_static();

        if self.len <= order {
            None
        } else {unsafe{
            let slice = slice::from_raw_parts(self.points, order + 1);
            self.points = self.points.offset(order as isize);
            self.len -= order;
            B::from_slice(slice)
        }}
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let order = B::order_static();
        let size = (self.len - (self.len - 1) % order) / order;
        (size, Some(size))
    }
}

impl<'a, F, B> DoubleEndedIterator for BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {
    fn next_back(&mut self) -> Option<B> {
        use std::slice;

        let order = B::order_static();

        // If there are any control points in the iterator that can't be used to create a full curve,
        // ignore them.
        let end = self.len - (self.len - 1) % order;
        if end <= order {
            None
        } else {unsafe{
            let slice = slice::from_raw_parts(self.points.offset((end-order-1) as isize), order + 1);
            self.len -= order;
            B::from_slice(slice)
        }}
    }
}

impl<'a, F, B> ExactSizeIterator for BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {}

pub trait BezCurve<F: Float>
        where Self: Sized
{
    type Point;
    type Vector;
    type Elevated;

    /// Attempt to create a curve from a slice. Fails if the slice's length does not match the
    /// curve's order + 1, or if it is being used to create an `NBez`/`NBezPoly`.
    fn from_slice(&[Self::Point]) -> Option<Self>;

    /// Perform interpolation on the curve for a value of `t` from `0.0` to `1.0` inclusive. Returns `None`
    /// if `t` is outside of that range.
    fn interp(&self, t: F) -> Option<Self::Point> {
        check_t_bounds!(t);
        Some(self.interp_unbounded(t))
    }
    /// Perform interpolation on the curve with no range bounds
    fn interp_unbounded(&self, t: F) -> Self::Point;

    /// Get the slope for the given `t`, bounded on `0.0` to `1.0` inclusive. Returns `None` if
    /// `t` is not within bounds.
    fn slope(&self, t: F) -> Option<Self::Vector> {
        check_t_bounds!(t);
        Some(self.slope_unbounded(t))
    }
    /// Get the slope for the given `t` with no range bounds
    fn slope_unbounded(&self, t: F) -> Self::Vector;

    fn elevate(&self) -> Self::Elevated;

    /// Gets the order of the curve
    fn order(&self) -> usize;
}

/// Gets the statically-known order of the curve
pub trait OrderStatic {
    fn order_static() -> usize;
}

#[derive(Clone, Copy)]
pub struct BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    points: C,
    phantom: PhantomData<(F, B)>
}

impl<F, B, C> BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    pub fn from_container(container: C) -> BezChain<F, B, C> {
        BezChain {
            points: container,
            phantom: PhantomData
        }
    }

    pub fn get(&self, index: usize) -> B {
        let order = B::order_static();
        let curve_index = index * order;
        B::from_slice(&self.points.as_ref()[curve_index..curve_index + order + 1]).unwrap()
    }

    pub fn iter(&self) -> BezIter<F, B> {
        BezIter {
            points: self.points.as_ref().as_ptr(),
            len: self.points.as_ref().len(),
            lifetime: PhantomData
        }
    }

    pub fn order(&self) -> usize {
        B::order_static()
    }

    pub fn unwrap(self) -> C {
        self.points
    }
}

impl<F, B, C> OrderStatic for BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    fn order_static() -> usize {
        B::order_static()
    }
}

impl<F, B, C> AsRef<C> for BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<F, B, C> AsMut<C> for BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}<commit_msg>Updated get() function on BezChain to return Option<B> instead of panicking<commit_after>extern crate num;

#[macro_use]
mod macros;
pub mod traitdefs;

mod nbez;
pub use nbez::*;

use traitdefs::Float;
use std::marker::PhantomData;

// There are macros in place to make it easier to create new bezier structs, as they can be created
// with a very consistent pattern. However, those macros are also written in a very consistent pattern
// which unfortunately is significantly harder, if not impossible, to create with a traditional
// macro. So, the macro invocations are generated with the build script and then inserted here.
include!(concat!(env!("OUT_DIR"), "/macro_invocs.rs"));

impl<F: Float> Vector2d<F> {
    pub fn perp(self) -> Vector2d<F> {
        Vector2d {
            x: -self.y,
            y: self.x
        }
    }
}

pub struct BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {
    points: *const B::Point,
    len: usize,
    lifetime: PhantomData<&'a ()>
}

impl<'a, F, B> Iterator for BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {
    type Item = B;
    fn next(&mut self) -> Option<B> {
        use std::slice;

        let order = B::order_static();

        if self.len <= order {
            None
        } else {unsafe{
            let slice = slice::from_raw_parts(self.points, order + 1);
            self.points = self.points.offset(order as isize);
            self.len -= order;
            B::from_slice(slice)
        }}
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let order = B::order_static();
        let size = (self.len - (self.len - 1) % order) / order;
        (size, Some(size))
    }
}

impl<'a, F, B> DoubleEndedIterator for BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {
    fn next_back(&mut self) -> Option<B> {
        use std::slice;

        let order = B::order_static();

        // If there are any control points in the iterator that can't be used to create a full curve,
        // ignore them.
        let end = self.len - (self.len - 1) % order;
        if end <= order {
            None
        } else {unsafe{
            let slice = slice::from_raw_parts(self.points.offset((end-order-1) as isize), order + 1);
            self.len -= order;
            B::from_slice(slice)
        }}
    }
}

impl<'a, F, B> ExactSizeIterator for BezIter<'a, F, B>
        where F: Float,
              B: BezCurve<F> + OrderStatic {}

pub trait BezCurve<F: Float>
        where Self: Sized
{
    type Point;
    type Vector;
    type Elevated;

    /// Attempt to create a curve from a slice. Fails if the slice's length does not match the
    /// curve's order + 1, or if it is being used to create an `NBez`/`NBezPoly`.
    fn from_slice(&[Self::Point]) -> Option<Self>;

    /// Perform interpolation on the curve for a value of `t` from `0.0` to `1.0` inclusive. Returns `None`
    /// if `t` is outside of that range.
    fn interp(&self, t: F) -> Option<Self::Point> {
        check_t_bounds!(t);
        Some(self.interp_unbounded(t))
    }
    /// Perform interpolation on the curve with no range bounds
    fn interp_unbounded(&self, t: F) -> Self::Point;

    /// Get the slope for the given `t`, bounded on `0.0` to `1.0` inclusive. Returns `None` if
    /// `t` is not within bounds.
    fn slope(&self, t: F) -> Option<Self::Vector> {
        check_t_bounds!(t);
        Some(self.slope_unbounded(t))
    }
    /// Get the slope for the given `t` with no range bounds
    fn slope_unbounded(&self, t: F) -> Self::Vector;

    fn elevate(&self) -> Self::Elevated;

    /// Gets the order of the curve
    fn order(&self) -> usize;
}

/// Gets the statically-known order of the curve
pub trait OrderStatic {
    fn order_static() -> usize;
}

#[derive(Clone, Copy)]
pub struct BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    points: C,
    phantom: PhantomData<(F, B)>
}

impl<F, B, C> BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    pub fn from_container(container: C) -> BezChain<F, B, C> {
        BezChain {
            points: container,
            phantom: PhantomData
        }
    }

    pub fn get(&self, index: usize) -> Option<B> {
        let len = self.points.as_ref().len();
        let order = B::order_static();
        let curve_index = index * order;
        let curve_end_index = index * order + order + 1;

        if curve_end_index > len - (len - 1) % order {
            None
        } else {
            Some(B::from_slice(&self.points.as_ref()[curve_index..curve_end_index]).unwrap())
        }
    }

    pub fn iter(&self) -> BezIter<F, B> {
        BezIter {
            points: self.points.as_ref().as_ptr(),
            len: self.points.as_ref().len(),
            lifetime: PhantomData
        }
    }

    pub fn order(&self) -> usize {
        B::order_static()
    }

    pub fn unwrap(self) -> C {
        self.points
    }
}

impl<F, B, C> OrderStatic for BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    fn order_static() -> usize {
        B::order_static()
    }
}

impl<F, B, C> AsRef<C> for BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    fn as_ref(&self) -> &C {
        &self.points
    }
}

impl<F, B, C> AsMut<C> for BezChain<F, B, C>
        where F: Float,
              B: BezCurve<F> + OrderStatic,
              C: AsRef<[B::Point]>
{
    fn as_mut(&mut self) -> &mut C {
        &mut self.points
    }
}<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate num;
extern crate nalgebra as na;

use glium::Surface;

static VSHADER_SOURCE: &'static str = r#"
    #version 150
    in vec3 position;
    in vec4 inner_color;
    in vec4 falloff_color;
    in float falloff;
    in float falloff_radius;
    in float inner_radius;
    out vec4 ginner_color;
    out vec4 gfalloff_color;
    out float gfalloff;
    out float gfalloff_radius;
    out float ginner_radius;
    uniform mat4 modelview;
    void main() {
        ginner_color = inner_color;
        gfalloff_color = falloff_color;
        gfalloff = falloff;
        gfalloff_radius = falloff_radius;
        ginner_radius = inner_radius;
        gl_Position = modelview * vec4(position, 1.0);
    }
"#;

static NODE_GSHADER_SOURCE: &'static str = r#"
    #version 150

    uniform mat4 projection;

    layout(points) in;
    layout(triangle_strip, max_vertices = 3) out;

    in vec4 ginner_color[1];
    in vec4 gfalloff_color[1];
    in float gfalloff[1];
    in float gfalloff_radius[1];
    in float ginner_radius[1];
    out vec2 delta;
    out vec4 finner_color;
    out vec4 ffalloff_color;
    out float finner_radius;
    out float ffalloff_radius;
    out float ffalloff;

    void main() {
        finner_color = ginner_color[0];
        ffalloff_color = ginner_color[0];
        finner_radius = ginner_radius[0];
        ffalloff = gfalloff[0];
        ffalloff_radius = gfalloff_radius[0];
        vec4 center = gl_in[0].gl_Position;
        float full_radius = finner_radius + ffalloff_radius;

        delta = full_radius * vec2(0, 2);
        gl_Position = projection * (center + vec4(delta, 0, 0));
        EmitVertex();

        delta = full_radius * vec2(-1.7320508075689, -1);
        gl_Position = projection * (center + vec4(delta, 0, 0));
        EmitVertex();

        delta = full_radius * vec2(1.7320508075689, -1);
        gl_Position = projection * (center + vec4(delta, 0, 0));
        EmitVertex();
    }
"#;

static EDGE_GSHADER_SOURCE: &'static str = r#"
    #version 150

    uniform mat4 projection;

    layout(lines) in;
    layout(triangle_strip, max_vertices = 12) out;

    in vec4 ginner_color[2];
    in vec4 gfalloff_color[2];
    in float gfalloff[2];
    in float gfalloff_radius[2];
    in float ginner_radius[2];
    out vec2 delta;
    out vec4 finner_color;
    out vec4 ffalloff_color;
    out float finner_radius;
    out float ffalloff_radius;
    out float ffalloff;

    void main() {
        vec4 first = gl_in[0].gl_Position;
        vec4 second = gl_in[1].gl_Position;

        vec2 net_delta = 2 * normalize(second.xy - first.xy);

        float radius;

        //Face 0

        //Vertex 0
        finner_color = ginner_color[0];
        ffalloff_color = gfalloff_color[0];
        finner_radius = ginner_radius[0];
        ffalloff_radius = gfalloff_radius[0];
        ffalloff = gfalloff[0];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(net_delta.y, -net_delta.x);
        gl_Position = projection * (first - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 1
        finner_color = ginner_color[0];
        ffalloff_color = gfalloff_color[0];
        finner_radius = ginner_radius[0];
        ffalloff_radius = gfalloff_radius[0];
        ffalloff = gfalloff[0];
        radius = finner_radius + ffalloff_radius;
        delta = radius * net_delta;
        gl_Position = projection * (first - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 2
        finner_color = ginner_color[0];
        ffalloff_color = gfalloff_color[0];
        finner_radius = ginner_radius[0];
        ffalloff_radius = gfalloff_radius[0];
        ffalloff = gfalloff[0];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(-net_delta.y, net_delta.x);
        gl_Position = projection * (first - vec4(delta, 0, 0));
        EmitVertex();

        EndPrimitive();

        //Face 1

        //Vertex 0
        finner_color = ginner_color[0];
        ffalloff_color = gfalloff_color[0];
        finner_radius = ginner_radius[0];
        ffalloff_radius = gfalloff_radius[0];
        ffalloff = gfalloff[0];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(net_delta.y, -net_delta.x);
        gl_Position = projection * (first - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 2
        finner_color = ginner_color[0];
        ffalloff_color = gfalloff_color[0];
        finner_radius = ginner_radius[0];
        ffalloff_radius = gfalloff_radius[0];
        ffalloff = gfalloff[0];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(-net_delta.y, net_delta.x);
        gl_Position = projection * (first - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 3
        finner_color = ginner_color[1];
        ffalloff_color = gfalloff_color[1];
        finner_radius = ginner_radius[1];
        ffalloff_radius = gfalloff_radius[1];
        ffalloff = gfalloff[1];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(net_delta.y, -net_delta.x);
        gl_Position = projection * (second - vec4(delta, 0, 0));
        EmitVertex();

        EndPrimitive();

        //Face 2

        //Vertex 2
        finner_color = ginner_color[0];
        ffalloff_color = gfalloff_color[0];
        finner_radius = ginner_radius[0];
        ffalloff_radius = gfalloff_radius[0];
        ffalloff = gfalloff[0];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(-net_delta.y, net_delta.x);
        gl_Position = projection * (first - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 4
        finner_color = ginner_color[1];
        ffalloff_color = gfalloff_color[1];
        finner_radius = ginner_radius[1];
        ffalloff_radius = gfalloff_radius[1];
        ffalloff = gfalloff[1];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(-net_delta.y, net_delta.x);
        gl_Position = projection * (second - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 3
        finner_color = ginner_color[1];
        ffalloff_color = gfalloff_color[1];
        finner_radius = ginner_radius[1];
        ffalloff_radius = gfalloff_radius[1];
        ffalloff = gfalloff[1];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(net_delta.y, -net_delta.x);
        gl_Position = projection * (second - vec4(delta, 0, 0));
        EmitVertex();

        EndPrimitive();

        //Face 3

        //Vertex 5
        finner_color = ginner_color[1];
        ffalloff_color = gfalloff_color[1];
        finner_radius = ginner_radius[1];
        ffalloff_radius = gfalloff_radius[1];
        ffalloff = gfalloff[1];
        radius = finner_radius + ffalloff_radius;
        delta = radius * net_delta;
        gl_Position = projection * (second + vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 3
        finner_color = ginner_color[1];
        ffalloff_color = gfalloff_color[1];
        finner_radius = ginner_radius[1];
        ffalloff_radius = gfalloff_radius[1];
        ffalloff = gfalloff[1];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(net_delta.y, -net_delta.x);
        gl_Position = projection * (second - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 4
        finner_color = ginner_color[1];
        ffalloff_color = gfalloff_color[1];
        finner_radius = ginner_radius[1];
        ffalloff_radius = gfalloff_radius[1];
        ffalloff = gfalloff[1];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(-net_delta.y, net_delta.x);
        gl_Position = projection * (second - vec4(delta, 0, 0));
        EmitVertex();

        EndPrimitive();
    }
"#;

static FSHADER_SOURCE: &'static str = r#"
    #version 150
    in vec2 delta;
    in vec4 finner_color;
    in vec4 ffalloff_color;
    in float finner_radius;
    in float ffalloff_radius;
    in float ffalloff;
    out vec4 color;
    void main() {
        float length = length(delta);
        if (length <= finner_radius) {
            float travel = length / finner_radius;
            // Manually interpolate the inner color into the falloff color.
            color = finner_color * (1 - travel) + ffalloff_color * travel;
        } else {
            color = vec4(ffalloff_color.xyz,
                ffalloff_color.a * max(0.0, 1.0 - pow((length - finner_radius) / ffalloff_radius, ffalloff)));
        }
    }
"#;

/// Node is used to pass nodes into the renderer.
#[derive(Copy, Clone)]
pub struct Node3 {
    pub position: [f32; 3],
    pub inner_color: [f32; 4],
    /// Decreasing falloff makes the nodes brightness more centered at the middle and increasing it makes it consistent.
    pub falloff: f32,
    pub falloff_color: [f32; 4],
    pub falloff_radius: f32,
    pub inner_radius: f32,
}

implement_vertex!(Node3,
                  position,
                  inner_color,
                  falloff,
                  falloff_color,
                  falloff_radius,
                  inner_radius);

pub struct Renderer<'a> {
    display: &'a glium::Display,
    node_program: glium::Program,
    edge_program: glium::Program,
    params: glium::DrawParameters<'a>,
}

/// A Renderer is tied to the lifetime of the glium Display and making one builds a GLSL program internally.
impl<'a> Renderer<'a> {
    /// Make a new Renderer from a glium::Display.
    pub fn new(display: &'a glium::Display) -> Self {
        Renderer {
            display: display,
            node_program: glium::Program::from_source(display,
                                                      VSHADER_SOURCE,
                                                      FSHADER_SOURCE,
                                                      Some(NODE_GSHADER_SOURCE))
                .unwrap(),
            edge_program: glium::Program::from_source(display,
                                                      VSHADER_SOURCE,
                                                      FSHADER_SOURCE,
                                                      Some(EDGE_GSHADER_SOURCE))
                .unwrap(),
            params: glium::DrawParameters {
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            },
        }
    }

    /// Take a modelview matrix, projection matrix, and a series of nodes and draw them in parallel on the GPU.
    pub fn render_nodes<S>(&self,
                           target: &mut S,
                           modelview: &[[f32; 4]; 4],
                           projection: &[[f32; 4]; 4],
                           nodes: &[Node3])
        where S: Surface
    {
        let vertex_buffer = glium::VertexBuffer::new(self.display, nodes).unwrap();
        let indices = glium::index::NoIndices(glium::index::PrimitiveType::Points);

        let uniforms = uniform! {
            modelview: *modelview,
            projection: *projection,
        };
        target.draw(&vertex_buffer,
                  &indices,
                  &self.node_program,
                  &uniforms,
                  &self.params)
            .unwrap();
    }

    /// Take a modelview matrix, projection matrix, and a series of lines (edges) and draw them in parallel on the GPU.
    pub fn render_edges<S>(&self,
                           target: &mut S,
                           modelview: &[[f32; 4]; 4],
                           projection: &[[f32; 4]; 4],
                           edges: &[Node3])
        where S: Surface
    {
        let vertex_buffer = glium::VertexBuffer::new(self.display, edges).unwrap();
        let indices = glium::index::NoIndices(glium::index::PrimitiveType::LinesList);

        let uniforms = uniform! {
            modelview: *modelview,
            projection: *projection,
        };
        target.draw(&vertex_buffer,
                  &indices,
                  &self.edge_program,
                  &uniforms,
                  &self.params)
            .unwrap();
    }
}
<commit_msg>should we really be bilboarding this?<commit_after>#[macro_use]
extern crate glium;
extern crate num;
extern crate nalgebra as na;

use glium::Surface;

static VSHADER_SOURCE: &'static str = r#"
    #version 150
    in vec3 position;
    in vec4 inner_color;
    in vec4 falloff_color;
    in float falloff;
    in float falloff_radius;
    in float inner_radius;
    out vec4 ginner_color;
    out vec4 gfalloff_color;
    out float gfalloff;
    out float gfalloff_radius;
    out float ginner_radius;
    uniform mat4 modelview;
    void main() {
        ginner_color = inner_color;
        gfalloff_color = falloff_color;
        gfalloff = falloff;
        gfalloff_radius = falloff_radius;
        ginner_radius = inner_radius;
        gl_Position = modelview * vec4(position, 1.0);
    }
"#;

static NODE_GSHADER_SOURCE: &'static str = r#"
    #version 150

    uniform mat4 projection;

    layout(points) in;
    layout(triangle_strip, max_vertices = 3) out;

    in vec4 ginner_color[1];
    in vec4 gfalloff_color[1];
    in float gfalloff[1];
    in float gfalloff_radius[1];
    in float ginner_radius[1];
    out vec2 delta;
    out vec4 finner_color;
    out vec4 ffalloff_color;
    out float finner_radius;
    out float ffalloff_radius;
    out float ffalloff;

    void main() {
        finner_color = ginner_color[0];
        ffalloff_color = ginner_color[0];
        finner_radius = ginner_radius[0];
        ffalloff = gfalloff[0];
        ffalloff_radius = gfalloff_radius[0];
        vec4 center = gl_in[0].gl_Position;
        float full_radius = finner_radius + ffalloff_radius;

        delta = full_radius * vec2(0, 2);
        gl_Position = projection * (center + vec4(delta, 0, 0));
        EmitVertex();

        delta = full_radius * vec2(-1.7320508075689, -1);
        gl_Position = projection * (center + vec4(delta, 0, 0));
        EmitVertex();

        delta = full_radius * vec2(1.7320508075689, -1);
        gl_Position = projection * (center + vec4(delta, 0, 0));
        EmitVertex();
    }
"#;

static EDGE_GSHADER_SOURCE: &'static str = r#"
    #version 150

    uniform mat4 projection;

    layout(lines) in;
    layout(triangle_strip, max_vertices = 12) out;

    in vec4 ginner_color[2];
    in vec4 gfalloff_color[2];
    in float gfalloff[2];
    in float gfalloff_radius[2];
    in float ginner_radius[2];
    out vec2 delta;
    out vec4 finner_color;
    out vec4 ffalloff_color;
    out float finner_radius;
    out float ffalloff_radius;
    out float ffalloff;

    void main() {
        vec4 first = gl_in[0].gl_Position;
        vec4 second = gl_in[1].gl_Position;

        vec3 full_delta = 2 * normalize(second.xyz - first.xyz);
        vec2 net_delta = 2 * normalize(second.xy - first.xy);

        float radius;

        //Face 0

        //Vertex 0
        finner_color = ginner_color[0];
        ffalloff_color = gfalloff_color[0];
        finner_radius = ginner_radius[0];
        ffalloff_radius = gfalloff_radius[0];
        ffalloff = gfalloff[0];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(net_delta.y, -net_delta.x);
        gl_Position = projection * (first - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 1
        finner_color = ginner_color[0];
        ffalloff_color = gfalloff_color[0];
        finner_radius = ginner_radius[0];
        ffalloff_radius = gfalloff_radius[0];
        ffalloff = gfalloff[0];
        radius = finner_radius + ffalloff_radius;
        delta = radius * net_delta;
        gl_Position = projection * (first - vec4(radius * full_delta, 0));
        EmitVertex();

        //Vertex 2
        finner_color = ginner_color[0];
        ffalloff_color = gfalloff_color[0];
        finner_radius = ginner_radius[0];
        ffalloff_radius = gfalloff_radius[0];
        ffalloff = gfalloff[0];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(-net_delta.y, net_delta.x);
        gl_Position = projection * (first - vec4(delta, 0, 0));
        EmitVertex();

        EndPrimitive();

        //Face 1

        //Vertex 0
        finner_color = ginner_color[0];
        ffalloff_color = gfalloff_color[0];
        finner_radius = ginner_radius[0];
        ffalloff_radius = gfalloff_radius[0];
        ffalloff = gfalloff[0];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(net_delta.y, -net_delta.x);
        gl_Position = projection * (first - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 2
        finner_color = ginner_color[0];
        ffalloff_color = gfalloff_color[0];
        finner_radius = ginner_radius[0];
        ffalloff_radius = gfalloff_radius[0];
        ffalloff = gfalloff[0];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(-net_delta.y, net_delta.x);
        gl_Position = projection * (first - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 3
        finner_color = ginner_color[1];
        ffalloff_color = gfalloff_color[1];
        finner_radius = ginner_radius[1];
        ffalloff_radius = gfalloff_radius[1];
        ffalloff = gfalloff[1];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(net_delta.y, -net_delta.x);
        gl_Position = projection * (second - vec4(delta, 0, 0));
        EmitVertex();

        EndPrimitive();

        //Face 2

        //Vertex 2
        finner_color = ginner_color[0];
        ffalloff_color = gfalloff_color[0];
        finner_radius = ginner_radius[0];
        ffalloff_radius = gfalloff_radius[0];
        ffalloff = gfalloff[0];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(-net_delta.y, net_delta.x);
        gl_Position = projection * (first - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 4
        finner_color = ginner_color[1];
        ffalloff_color = gfalloff_color[1];
        finner_radius = ginner_radius[1];
        ffalloff_radius = gfalloff_radius[1];
        ffalloff = gfalloff[1];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(-net_delta.y, net_delta.x);
        gl_Position = projection * (second - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 3
        finner_color = ginner_color[1];
        ffalloff_color = gfalloff_color[1];
        finner_radius = ginner_radius[1];
        ffalloff_radius = gfalloff_radius[1];
        ffalloff = gfalloff[1];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(net_delta.y, -net_delta.x);
        gl_Position = projection * (second - vec4(delta, 0, 0));
        EmitVertex();

        EndPrimitive();

        //Face 3

        //Vertex 5
        finner_color = ginner_color[1];
        ffalloff_color = gfalloff_color[1];
        finner_radius = ginner_radius[1];
        ffalloff_radius = gfalloff_radius[1];
        ffalloff = gfalloff[1];
        radius = finner_radius + ffalloff_radius;
        delta = radius * net_delta;
        gl_Position = projection * (second + vec4(radius * full_delta, 0));
        EmitVertex();

        //Vertex 3
        finner_color = ginner_color[1];
        ffalloff_color = gfalloff_color[1];
        finner_radius = ginner_radius[1];
        ffalloff_radius = gfalloff_radius[1];
        ffalloff = gfalloff[1];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(net_delta.y, -net_delta.x);
        gl_Position = projection * (second - vec4(delta, 0, 0));
        EmitVertex();

        //Vertex 4
        finner_color = ginner_color[1];
        ffalloff_color = gfalloff_color[1];
        finner_radius = ginner_radius[1];
        ffalloff_radius = gfalloff_radius[1];
        ffalloff = gfalloff[1];
        radius = finner_radius + ffalloff_radius;
        delta = radius * vec2(-net_delta.y, net_delta.x);
        gl_Position = projection * (second - vec4(delta, 0, 0));
        EmitVertex();

        EndPrimitive();
    }
"#;

static FSHADER_SOURCE: &'static str = r#"
    #version 150
    in vec2 delta;
    in vec4 finner_color;
    in vec4 ffalloff_color;
    in float finner_radius;
    in float ffalloff_radius;
    in float ffalloff;
    out vec4 color;
    void main() {
        float length = length(delta);
        if (length <= finner_radius) {
            float travel = length / finner_radius;
            // Manually interpolate the inner color into the falloff color.
            color = finner_color * (1 - travel) + ffalloff_color * travel;
        } else {
            color = vec4(ffalloff_color.xyz,
                ffalloff_color.a * max(0.0, 1.0 - pow((length - finner_radius) / ffalloff_radius, ffalloff)));
        }
    }
"#;

/// Node is used to pass nodes into the renderer.
#[derive(Copy, Clone)]
pub struct Node3 {
    pub position: [f32; 3],
    pub inner_color: [f32; 4],
    /// Decreasing falloff makes the nodes brightness more centered at the middle and increasing it makes it consistent.
    pub falloff: f32,
    pub falloff_color: [f32; 4],
    pub falloff_radius: f32,
    pub inner_radius: f32,
}

implement_vertex!(Node3,
                  position,
                  inner_color,
                  falloff,
                  falloff_color,
                  falloff_radius,
                  inner_radius);

pub struct Renderer<'a> {
    display: &'a glium::Display,
    node_program: glium::Program,
    edge_program: glium::Program,
    params: glium::DrawParameters<'a>,
}

/// A Renderer is tied to the lifetime of the glium Display and making one builds a GLSL program internally.
impl<'a> Renderer<'a> {
    /// Make a new Renderer from a glium::Display.
    pub fn new(display: &'a glium::Display) -> Self {
        Renderer {
            display: display,
            node_program: glium::Program::from_source(display,
                                                      VSHADER_SOURCE,
                                                      FSHADER_SOURCE,
                                                      Some(NODE_GSHADER_SOURCE))
                .unwrap(),
            edge_program: glium::Program::from_source(display,
                                                      VSHADER_SOURCE,
                                                      FSHADER_SOURCE,
                                                      Some(EDGE_GSHADER_SOURCE))
                .unwrap(),
            params: glium::DrawParameters {
                blend: glium::Blend::alpha_blending(),
                ..Default::default()
            },
        }
    }

    /// Take a modelview matrix, projection matrix, and a series of nodes and draw them in parallel on the GPU.
    pub fn render_nodes<S>(&self,
                           target: &mut S,
                           modelview: &[[f32; 4]; 4],
                           projection: &[[f32; 4]; 4],
                           nodes: &[Node3])
        where S: Surface
    {
        let vertex_buffer = glium::VertexBuffer::new(self.display, nodes).unwrap();
        let indices = glium::index::NoIndices(glium::index::PrimitiveType::Points);

        let uniforms = uniform! {
            modelview: *modelview,
            projection: *projection,
        };
        target.draw(&vertex_buffer,
                  &indices,
                  &self.node_program,
                  &uniforms,
                  &self.params)
            .unwrap();
    }

    /// Take a modelview matrix, projection matrix, and a series of lines (edges) and draw them in parallel on the GPU.
    pub fn render_edges<S>(&self,
                           target: &mut S,
                           modelview: &[[f32; 4]; 4],
                           projection: &[[f32; 4]; 4],
                           edges: &[Node3])
        where S: Surface
    {
        let vertex_buffer = glium::VertexBuffer::new(self.display, edges).unwrap();
        let indices = glium::index::NoIndices(glium::index::PrimitiveType::LinesList);

        let uniforms = uniform! {
            modelview: *modelview,
            projection: *projection,
        };
        target.draw(&vertex_buffer,
                  &indices,
                  &self.edge_program,
                  &uniforms,
                  &self.params)
            .unwrap();
    }
}
<|endoftext|>


<commit_before>//! This crate provides connectivity to the APRS amateur radio network over the internet.
//!
//! APRS (Automatic Packet Reporting System) is a packet-based, internet- and rf-connected
//! communication network for amateur radio operators and enthusiasts that allows transport
//! of location data, weather reports and more among operators. See the [APRS website][1]
//! for a detailed description of the network.
//!
//! Credits:
//! --------
//! APRS (c) Bob Bruninga, WB4APR
//! [Original Python module][2] by Greg Albrecht, W2GMD
//! Rust port by Jeffrey Hoover, KI6SGV
//!
//! This library is licensed under the Apache 2.0 license. See [LICENSE][2] for full terms.
//!
//! [1]: http://www.aprs.org/
//! [2]: https://www.github.com/ampledata/aprs
//! [3]: https://www.apache.org/licenses/LICENSE-2.0

#[macro_use]
extern crate lazy_static;

pub mod constants;
pub mod util;
pub mod geo_util;
pub mod fcs;
pub mod functions;
pub mod structs;
pub mod decimaldegrees;
pub mod kiss_structs;
<commit_msg>Require byteorder and bit_vec<commit_after>//! This crate provides connectivity to the APRS amateur radio network over the internet.
//!
//! APRS (Automatic Packet Reporting System) is a packet-based, internet- and rf-connected
//! communication network for amateur radio operators and enthusiasts that allows transport
//! of location data, weather reports and more among operators. See the [APRS website][1]
//! for a detailed description of the network.
//!
//! Credits:
//! --------
//! APRS (c) Bob Bruninga, WB4APR
//! [Original Python module][2] by Greg Albrecht, W2GMD
//! Rust port by Jeffrey Hoover, KI6SGV
//!
//! This library is licensed under the Apache 2.0 license. See [LICENSE][2] for full terms.
//!
//! [1]: http://www.aprs.org/
//! [2]: https://www.github.com/ampledata/aprs
//! [3]: https://www.apache.org/licenses/LICENSE-2.0

#[macro_use]
extern crate lazy_static;

extern crate byteorder;
extern crate bit_vec;

pub mod constants;
pub mod util;
pub mod geo_util;
pub mod fcs;
pub mod functions;
pub mod structs;
pub mod decimaldegrees;
pub mod kiss_structs;
<|endoftext|>


<commit_before>extern crate rand;
use HaltCondition::{ Epochs, MSE };
use UpdateRule::{ Stochastic, Batch };
use std::iter::{Zip, Enumerate};
use std::slice;
use std::num::Float;

static DEFAULT_LEARNING_RATE: f64 = 0.3f64;
static DEFAULT_MOMENTUM: f64 = 0f64;
static DEFAULT_EPOCHS: usize = 1000;

#[test]
fn it_works() {
}

type Node = Vec<f64>;
type Layer = Vec<Node>;

#[derive(Debug)]
#[derive(Clone)]
pub enum HaltCondition {
    Epochs(usize),
    MSE(f64),
}

#[derive(Debug)]
#[derive(Clone)]
pub enum UpdateRule {
    Stochastic,
    Batch
}

#[derive(Debug)]
pub struct Trainer<'a,'b> {
    examples: &'b [(&'b Vec<f64>, &'b Vec<f64>)],
    rate: f64,
    momentum: f64,
    log_interval: Option<usize>,
    halt_condition: HaltCondition,
    update_rule: UpdateRule,
    threads: usize,
    nn: &'a mut NN,
}

impl<'a,'b> Trainer<'a,'b>  {

    pub fn rate(&mut self, rate: f64) -> &mut Trainer<'a,'b> {
        self.rate = rate;
        self
    }

    pub fn momentum(&mut self, momentum: f64) -> &mut Trainer<'a,'b> {
        self.momentum = momentum;
        self
    }

    pub fn log_interval(&mut self, log_interval: Option<usize>) -> &mut Trainer<'a,'b> {
        self.log_interval = log_interval;
        self
    }

    pub fn halt_condition(&mut self, halt_condition: HaltCondition) -> &mut Trainer<'a,'b> {
        self.halt_condition = halt_condition;
        self
    }

    pub fn update_rule(&mut self, update_rule: UpdateRule) -> &mut Trainer<'a,'b> {
        self.update_rule = update_rule;
        self
    }

    pub fn threads(&mut self, threads: usize) -> &mut Trainer<'a,'b> {
        self.threads = threads;
        self
    }

    pub fn go(&mut self) -> Result<usize, &str> {
        self.nn.train_details(
            self.examples,
            self.rate,
            self.momentum,
            self.log_interval,
            self.halt_condition.clone(),
            self.update_rule.clone(),
            self.threads
        )
    }

}

#[derive(Debug)]
#[derive(Clone)]
pub struct NN {
    layers: Vec<Layer>,
    num_inputs: usize,
}

impl NN {
    pub fn run(&self, inputs: &Vec<f64>) -> Vec<f64> {
        self.do_run(inputs).pop().unwrap()
    }

    pub fn train<'b>(&'b mut self, examples: &'b [(&'b Vec<f64>, &'b Vec<f64>)]) -> Trainer {
        Trainer {
            examples: examples,
            rate: DEFAULT_LEARNING_RATE,
            momentum: DEFAULT_MOMENTUM,
            log_interval: None,
            halt_condition: Epochs(DEFAULT_EPOCHS),
            update_rule: Stochastic,
            threads: 1,
            nn: self
        }
    }

    // returns a results with ok being the error rate of the network found at the end and
    // Err is a string with an explaination
    fn train_details(&mut self, examples: &[(&Vec<f64>, &Vec<f64>)], rate: f64, momentum: f64, log_interval: Option<usize>,
                    halt_condition: HaltCondition, update_rule: UpdateRule, threads: usize) -> Result<usize, &str> {

        let mut epochs = 0;
        let mut error_rate = 0.0;

        loop {

            let mut prev_deltas = self.make_weights_tracker(0.0f64);
            let mut batch_data = self.make_weights_tracker(0.0f64);
            let mut error_sum: f64 = 0.0;

            for &(inputs, targets) in examples.iter() {
                let results = self.do_run(inputs);
                let weight_updates = self.calculate_weight_updates(&results, &targets);
                error_sum += calculate_error(&results, targets);
                match update_rule {
                    Batch => update_batch_data(&mut batch_data, &weight_updates),
                    Stochastic => self.update_weights(&weight_updates, &mut prev_deltas, rate, momentum),
                }
            }

            // if we're in batch mode, update the weights now
            match update_rule {
                Batch => self.update_weights(&batch_data, &mut prev_deltas, rate, momentum),
                Stochastic => (),
            }

            epochs += 1;

            // log error rate if neccessary
            match log_interval {
                Some(interval) if epochs % interval == 0 => {
                    println!("error rate: {}", error_rate);
                },
                _ => (),
            }

            // check if we've met the halt condition yet
            match halt_condition {
                Epochs(epochs_halt) => {
                    if epochs == epochs_halt { break; }
                },
                MSE(target_error) => {
                    if target_error == error_rate { break; }
                }
            }
        }

        unimplemented!();
    }

    fn do_run(&self, inputs: &Vec<f64>) -> Vec<Vec<f64>> {
        let mut results = Vec::new();
        results.push(inputs.clone());
        for (layer_index, layer) in self.layers.iter().enumerate() {
            let mut layer_results = Vec::new();
            for node in layer.iter() {
                layer_results.push( sigmoid(modified_dotprod(&node, &results[layer_index])) )
            }
            results.push(layer_results.clone());
        }
        results
    }

    // updates all weights in the network
    fn update_weights(&mut self, network_weight_updates: &Vec<Vec<Vec<f64>>>, prev_deltas: &mut Vec<Vec<Vec<f64>>>, rate: f64, momentum: f64) {
        for layer_index in 0..self.layers.len() {
            let mut layer = &mut self.layers[layer_index];
            let layer_weight_updates = &network_weight_updates[layer_index];
            for node_index in 0..layer.len() {
                let mut node = &mut layer[node_index];
                let node_weight_updates = &layer_weight_updates[node_index];
                for weight_index in 0..node.len() {
                    let weight_update = node_weight_updates[weight_index];
                    let prev_delta = prev_deltas[layer_index][node_index][weight_index];
                    let delta = (rate * weight_update) + (momentum * prev_delta);
                    node[weight_index] += delta;
                    prev_deltas[layer_index][node_index][weight_index] = delta;
                }
            }
        }
    }

    // calculates all weight updates by backpropagation
    fn calculate_weight_updates(&self, results: &Vec<Vec<f64>>, targets: &[f64]) -> Vec<Vec<Vec<f64>>> {
        let mut network_errors:Vec<Vec<f64>> = Vec::new();
        let mut network_weight_updates = Vec::new();

        let layers = &self.layers;
        let network_results = &results[1..]; // skip the input layer

        for (layer_index, (layer_nodes, layer_results)) in iter_zip_enum(layers, network_results) {
            let prev_layer_results = &results[layer_index];
            let mut layer_errors = Vec::new();
            let mut layer_weight_updates = Vec::new();

            let next_layer_nodes: &Layer = &&layers[layer_index+1];

            for (node_index, (node, &result)) in iter_zip_enum(layer_nodes, layer_results) {
                let mut node_weight_updates = Vec::new();
                let mut node_error;

                // calculate error for this node
                if layer_index == layers.len() - 1 {
                    node_error = result * (1f64 - result) * (targets[node_index] - result);
                } else {
                    let mut sum = 0f64;
                    for (next_node, &next_node_error_data) in next_layer_nodes.iter().zip((&network_errors[layer_index]).iter()) { // TODO: make sure that layer_index is the correct index, maybe +/-1
                        sum += next_node[node_index+1] * next_node_error_data; // +1 because the 0th weight is the threshold
                    }
                    node_error = result * (1f64 - result) * sum;
                }

                // calculate weight updates for this node
                for weight_index in 0..node.len() {
                    let mut prev_layer_result;
                    if weight_index == 0 {
                        prev_layer_result = 1f64; // theshold
                    } else {
                        prev_layer_result = prev_layer_results[weight_index-1];
                    }
                    let weight_update = node_error * prev_layer_result;
                    node_weight_updates.push(weight_update);
                }

                layer_errors.push(node_error);
                layer_weight_updates.push(node_weight_updates);
            }

            network_errors.push(layer_errors);
            network_weight_updates.push(layer_weight_updates);
        }

        // updates were build by backpropagation so reverse them
        network_weight_updates.reverse();

        network_weight_updates
    }

    fn make_weights_tracker<T: Clone>(&self, place_holder: T) -> Vec<Vec<Vec<T>>> {
        let mut network_level = Vec::new();
        for layer in self.layers.iter() {
            let mut layer_level = Vec::new();
            for node in layer.iter() {
                let mut node_level = Vec::new();
                for _ in node.iter() {
                    node_level.push(place_holder.clone());
                }
                layer_level.push(node_level);
            }
            network_level.push(layer_level);
        }

        network_level
    }
}

fn modified_dotprod(node: &Node, values: &Vec<f64>) -> f64 {
    let mut total = node[0]; // for the threshold weight
    for (weight, value) in node.iter().skip(1).zip(values.iter()) {
        total += weight * value;
    }
    total
}

fn sigmoid(y: f64) -> f64 {
    1f64 / (1f64 + Float::exp(-y))
}

// adds new network weight updates into the update updates already collected
fn update_batch_data(batch_data: &mut Vec<Vec<Vec<f64>>> , network_weight_updates: &Vec<Vec<Vec<f64>>>) {
    for layer_index in 0..batch_data.len() {
        let mut batch_layer = &mut batch_data[layer_index];
        let layer_weight_updates = &network_weight_updates[layer_index];
        for node_index in 0..batch_layer.len() {
            let mut batch_node = &mut batch_layer[node_index];
            let node_weight_updates = &layer_weight_updates[node_index];
            for weight_index in 0..batch_node.len() {
                batch_node[weight_index] += node_weight_updates[weight_index];
            }
        }
    }
}

fn iter_zip_enum<'s, 't, S: 's, T: 't>(s: &'s [S], t: &'t [T]) ->
    Enumerate<Zip<slice::Iter<'s, S>, slice::Iter<'t, T>>>  {
    s.iter().zip(t.iter()).enumerate()
}

fn calculate_error(results: &Vec<Vec<f64>>, targets: &[f64]) -> f64 {
    unimplemented!()
}

pub fn new(layers_sizes: &[usize]) -> NN {
    if layers_sizes.len() < 2 {
        panic!("must have at least two layers");
    }
    let mut layers = Vec::new();
    let mut it = layers_sizes.iter();
    // get the first layer size
    let first_layer_size = *it.next().unwrap();

    // setup the rest of the layers
    let mut prev_layer_size = first_layer_size;
    for &layer_size in it {
        let mut layer: Layer = Vec::new();
        for _ in 0..layer_size {
            let mut node: Node = vec![rand::random(); prev_layer_size];
            node.shrink_to_fit();
            layer.push(node)
        }
        layer.shrink_to_fit();
        layers.push(layer);
        prev_layer_size = layer_size;
    }
    layers.shrink_to_fit();
    NN { layers: layers, num_inputs: first_layer_size }
}

<commit_msg>fixed next layer index error<commit_after>extern crate rand;
use HaltCondition::{ Epochs, MSE };
use UpdateRule::{ Stochastic, Batch };
use std::iter::{Zip, Enumerate};
use std::slice;
use std::num::Float;

static DEFAULT_LEARNING_RATE: f64 = 0.3f64;
static DEFAULT_MOMENTUM: f64 = 0f64;
static DEFAULT_EPOCHS: usize = 1000;

#[test]
fn it_works() {
}

type Node = Vec<f64>;
type Layer = Vec<Node>;

#[derive(Debug)]
#[derive(Clone)]
pub enum HaltCondition {
    Epochs(usize),
    MSE(f64),
}

#[derive(Debug)]
#[derive(Clone)]
pub enum UpdateRule {
    Stochastic,
    Batch
}

#[derive(Debug)]
pub struct Trainer<'a,'b> {
    examples: &'b [(Vec<f64>, Vec<f64>)],
    rate: f64,
    momentum: f64,
    log_interval: Option<usize>,
    halt_condition: HaltCondition,
    update_rule: UpdateRule,
    threads: usize,
    nn: &'a mut NN,
}

impl<'a,'b> Trainer<'a,'b>  {

    pub fn rate(&mut self, rate: f64) -> &mut Trainer<'a,'b> {
        self.rate = rate;
        self
    }

    pub fn momentum(&mut self, momentum: f64) -> &mut Trainer<'a,'b> {
        self.momentum = momentum;
        self
    }

    pub fn log_interval(&mut self, log_interval: Option<usize>) -> &mut Trainer<'a,'b> {
        self.log_interval = log_interval;
        self
    }

    pub fn halt_condition(&mut self, halt_condition: HaltCondition) -> &mut Trainer<'a,'b> {
        self.halt_condition = halt_condition;
        self
    }

    pub fn update_rule(&mut self, update_rule: UpdateRule) -> &mut Trainer<'a,'b> {
        self.update_rule = update_rule;
        self
    }

    pub fn threads(&mut self, threads: usize) -> &mut Trainer<'a,'b> {
        self.threads = threads;
        self
    }

    pub fn go(&mut self) -> Result<usize, &str> {
        self.nn.train_details(
            self.examples,
            self.rate,
            self.momentum,
            self.log_interval,
            self.halt_condition.clone(),
            self.update_rule.clone(),
            self.threads
        )
    }

}

#[derive(Debug)]
#[derive(Clone)]
pub struct NN {
    layers: Vec<Layer>,
    num_inputs: usize,
}

impl NN {
    pub fn run(&self, inputs: &Vec<f64>) -> Vec<f64> {
        self.do_run(inputs).pop().unwrap()
    }

    pub fn train<'b>(&'b mut self, examples: &'b [(Vec<f64>, Vec<f64>)]) -> Trainer {
        Trainer {
            examples: examples,
            rate: DEFAULT_LEARNING_RATE,
            momentum: DEFAULT_MOMENTUM,
            log_interval: None,
            halt_condition: Epochs(DEFAULT_EPOCHS),
            update_rule: Stochastic,
            threads: 1,
            nn: self
        }
    }

    // returns a results with ok being the error rate of the network found at the end and
    // Err is a string with an explaination
    fn train_details(&mut self, examples: &[(Vec<f64>, Vec<f64>)], rate: f64, momentum: f64, log_interval: Option<usize>,
                    halt_condition: HaltCondition, update_rule: UpdateRule, threads: usize) -> Result<usize, &str> {

        let mut epochs = 0;
        let mut error_rate = 0.0;

        loop {

            let mut prev_deltas = self.make_weights_tracker(0.0f64);
            let mut batch_data = self.make_weights_tracker(0.0f64);
            let mut error_sum: f64 = 0.0;

            for &(ref inputs, ref targets) in examples.iter() {
                let results = self.do_run(&inputs);
                let weight_updates = self.calculate_weight_updates(&results, &targets);
                error_sum += calculate_error(&results, &targets);
                match update_rule {
                    Batch => update_batch_data(&mut batch_data, &weight_updates),
                    Stochastic => self.update_weights(&weight_updates, &mut prev_deltas, rate, momentum),
                }
            }

            // if we're in batch mode, update the weights now
            match update_rule {
                Batch => self.update_weights(&batch_data, &mut prev_deltas, rate, momentum),
                Stochastic => (),
            }

            epochs += 1;

            // log error rate if neccessary
            match log_interval {
                Some(interval) if epochs % interval == 0 => {
                    println!("error rate: {}", error_rate);
                },
                _ => (),
            }

            // check if we've met the halt condition yet
            match halt_condition {
                Epochs(epochs_halt) => {
                    if epochs == epochs_halt { break; }
                },
                MSE(target_error) => {
                    if target_error == error_rate { break; }
                }
            }
        }

        unimplemented!();
    }

    fn do_run(&self, inputs: &Vec<f64>) -> Vec<Vec<f64>> {
        let mut results = Vec::new();
        results.push(inputs.clone());
        for (layer_index, layer) in self.layers.iter().enumerate() {
            let mut layer_results = Vec::new();
            for node in layer.iter() {
                layer_results.push( sigmoid(modified_dotprod(&node, &results[layer_index])) )
            }
            results.push(layer_results.clone());
        }
        results
    }

    // updates all weights in the network
    fn update_weights(&mut self, network_weight_updates: &Vec<Vec<Vec<f64>>>, prev_deltas: &mut Vec<Vec<Vec<f64>>>, rate: f64, momentum: f64) {
        for layer_index in 0..self.layers.len() {
            let mut layer = &mut self.layers[layer_index];
            let layer_weight_updates = &network_weight_updates[layer_index];
            for node_index in 0..layer.len() {
                let mut node = &mut layer[node_index];
                let node_weight_updates = &layer_weight_updates[node_index];
                for weight_index in 0..node.len() {
                    let weight_update = node_weight_updates[weight_index];
                    let prev_delta = prev_deltas[layer_index][node_index][weight_index];
                    let delta = (rate * weight_update) + (momentum * prev_delta);
                    node[weight_index] += delta;
                    prev_deltas[layer_index][node_index][weight_index] = delta;
                }
            }
        }
    }

    // calculates all weight updates by backpropagation
    fn calculate_weight_updates(&self, results: &Vec<Vec<f64>>, targets: &[f64]) -> Vec<Vec<Vec<f64>>> {
        let mut network_errors:Vec<Vec<f64>> = Vec::new();
        let mut network_weight_updates = Vec::new();
        let layers = &self.layers;
        let network_results = &results[1..]; // skip the input layer

        // let mut layer_index = layers.len();

        for (layer_index, (layer_nodes, layer_results)) in iter_zip_enum(layers, network_results).rev() { //TODO: just use zip here
            // layer_index -= 1;
            let prev_layer_results = &results[layer_index];
            let mut layer_errors = Vec::new();
            let mut layer_weight_updates = Vec::new();

            // let next_layer_nodes: &Layer = &&layers[layer_index+1];

            for (node_index, (node, &result)) in iter_zip_enum(layer_nodes, layer_results) {
                let mut node_weight_updates = Vec::new();
                let mut node_error;

                // calculate error for this node
                if layer_index == layers.len() - 1 {
                    node_error = result * (1f64 - result) * (targets[node_index] - result);
                } else {
                    let mut sum = 0f64;
                    for (next_node, &next_node_error_data) in layers[layer_index].iter().zip((&network_errors[layer_index]).iter()) { // TODO: make sure that layer_index is the correct index, maybe +/-1
                        sum += next_node[node_index+1] * next_node_error_data; // +1 because the 0th weight is the threshold
                    }
                    node_error = result * (1f64 - result) * sum;
                }

                // calculate weight updates for this node
                for weight_index in 0..node.len() {
                    let mut prev_layer_result;
                    if weight_index == 0 {
                        prev_layer_result = 1f64; // theshold
                    } else {
                        prev_layer_result = prev_layer_results[weight_index-1];
                    }
                    let weight_update = node_error * prev_layer_result;
                    node_weight_updates.push(weight_update);
                }

                layer_errors.push(node_error);
                layer_weight_updates.push(node_weight_updates);
            }

            network_errors.push(layer_errors);
            network_weight_updates.push(layer_weight_updates);
        }

        // updates were build by backpropagation so reverse them
        network_weight_updates.reverse();

        network_weight_updates
    }

    fn make_weights_tracker<T: Clone>(&self, place_holder: T) -> Vec<Vec<Vec<T>>> {
        let mut network_level = Vec::new();
        for layer in self.layers.iter() {
            let mut layer_level = Vec::new();
            for node in layer.iter() {
                let mut node_level = Vec::new();
                for _ in node.iter() {
                    node_level.push(place_holder.clone());
                }
                layer_level.push(node_level);
            }
            network_level.push(layer_level);
        }

        network_level
    }
}

fn modified_dotprod(node: &Node, values: &Vec<f64>) -> f64 {
    let mut total = node[0]; // for the threshold weight
    for (weight, value) in node.iter().skip(1).zip(values.iter()) {
        total += weight * value;
    }
    total
}

fn sigmoid(y: f64) -> f64 {
    1f64 / (1f64 + Float::exp(-y))
}

// adds new network weight updates into the update updates already collected
fn update_batch_data(batch_data: &mut Vec<Vec<Vec<f64>>> , network_weight_updates: &Vec<Vec<Vec<f64>>>) {
    for layer_index in 0..batch_data.len() {
        let mut batch_layer = &mut batch_data[layer_index];
        let layer_weight_updates = &network_weight_updates[layer_index];
        for node_index in 0..batch_layer.len() {
            let mut batch_node = &mut batch_layer[node_index];
            let node_weight_updates = &layer_weight_updates[node_index];
            for weight_index in 0..batch_node.len() {
                batch_node[weight_index] += node_weight_updates[weight_index];
            }
        }
    }
}

fn iter_zip_enum<'s, 't, S: 's, T: 't>(s: &'s [S], t: &'t [T]) ->
    Enumerate<Zip<slice::Iter<'s, S>, slice::Iter<'t, T>>>  {
    s.iter().zip(t.iter()).enumerate()
}

fn calculate_error(results: &Vec<Vec<f64>>, targets: &[f64]) -> f64 {
    unimplemented!()
}

pub fn new(layers_sizes: &[usize]) -> NN {
    if layers_sizes.len() < 2 {
        panic!("must have at least two layers");
    }
    let mut layers = Vec::new();
    let mut it = layers_sizes.iter();
    // get the first layer size
    let first_layer_size = *it.next().unwrap();

    // setup the rest of the layers
    let mut prev_layer_size = first_layer_size;
    for &layer_size in it {
        let mut layer: Layer = Vec::new();
        for _ in 0..layer_size {
            let mut node: Node = vec![rand::random(); prev_layer_size];
            node.shrink_to_fit();
            layer.push(node)
        }
        layer.shrink_to_fit();
        layers.push(layer);
        prev_layer_size = layer_size;
    }
    layers.shrink_to_fit();
    NN { layers: layers, num_inputs: first_layer_size }
}

<|endoftext|>


<commit_before>
#![allow(dead_code)]

pub extern crate crypto;

use crypto::digest::Digest;

pub trait Hashable {
    fn to_bytes(&self) -> &[u8];
}

impl Hashable for String {
    fn to_bytes(&self) -> &[u8] {
        return self.as_bytes();
    }
}

fn make_hash<D, T>(digest: &mut D, bytes: &[u8]) -> Vec<u8> where D: Digest {
    let mut hash = vec![0; digest.output_bytes()];

    digest.reset();
    digest.input(bytes);
    digest.result(&mut hash);
    digest.reset();

    hash
}

fn combine_hashes<D>(digest: &mut D, left: &[u8], right: &[u8]) -> Vec<u8> where D: Digest {
    let mut hash = vec![0; digest.output_bytes()];

    digest.reset();
    digest.input(left);
    digest.input(right);
    digest.result(&mut hash);
    digest.reset();

    hash
}

enum Tree<T> {
    Leaf {
        hash: Vec<u8>,
        value: T
    },

    Node {
        hash: Vec<u8>,
        left: Box<Tree<T>>,
        right: Box<Tree<T>>
    }
}

impl <T> Tree<T> where T: Hashable {

    fn new(hash: Vec<u8>, value: T) -> Self {
        Tree::Leaf {
            hash: hash,
            value: value
        }
    }

    fn get_hash(&self) -> &Vec<u8> {
        match *self {
            Tree::Leaf { ref hash, value: _ }          => hash,
            Tree::Node { ref hash, left: _, right: _ } => hash
        }
    }
}

fn make_leaf<D, T>(digest: &mut D, value: T) -> Tree<T> where D: Digest, T: Hashable {
    let hash = make_hash::<D, T>(digest, value.to_bytes());
    Tree::new(hash, value)
}

pub struct MerkleTree<D, T> where D: Digest, T: Hashable {
    digest: D,
    tree: Tree<T>
}

impl <D, T> MerkleTree<D, T> where D: Digest, T: Hashable {

    pub fn from_vec(mut digest: D, values: Vec<T>) -> Self {
        if values.is_empty() {
            panic!("Cannot build a Merkle tree from an empty vector.");
        }

        let len = values.len();
        let mut cur = Vec::with_capacity(len);

        for v in values {
            let leaf = make_leaf(&mut digest, v);
            cur.push(leaf);
        }

        while cur.len() > 1 {
            let mut next = Vec::with_capacity(len);

            while cur.len() > 0 {
                if cur.len() == 1 {
                    next.push(cur.remove(0));
                }
                else {
                    let left  = cur.remove(0);
                    let right = cur.remove(0);

                    let combined_hash = combine_hashes::<D>(
                        &mut digest,
                        left.get_hash().as_slice(),
                        right.get_hash().as_slice()
                    );

                    let node = Tree::Node {
                       hash: combined_hash,
                       left: Box::new(left),
                       right: Box::new(right)
                    };

                    next.push(node);
                }
            }

            cur = next;
        }

        let tree = cur.remove(0);

        MerkleTree {
            digest: digest,
            tree: tree
        }
    }

}

#[cfg(test)]
use crypto::sha3::Sha3;

#[test]
fn test_stuff() {
}

#[cfg(test)]
pub mod tests;
<commit_msg>Reverse Vec and use pop() instead of remove(0) for effiency.<commit_after>
#![allow(dead_code)]

pub extern crate crypto;

use crypto::digest::Digest;

pub trait Hashable {
    fn to_bytes(&self) -> &[u8];
}

impl Hashable for String {
    fn to_bytes(&self) -> &[u8] {
        return self.as_bytes();
    }
}

fn make_hash<D, T>(digest: &mut D, bytes: &[u8]) -> Vec<u8> where D: Digest {
    let mut hash = vec![0; digest.output_bytes()];

    digest.reset();
    digest.input(bytes);
    digest.result(&mut hash);
    digest.reset();

    hash
}

fn combine_hashes<D>(digest: &mut D, left: &[u8], right: &[u8]) -> Vec<u8> where D: Digest {
    let mut hash = vec![0; digest.output_bytes()];

    digest.reset();
    digest.input(left);
    digest.input(right);
    digest.result(&mut hash);
    digest.reset();

    hash
}

enum Tree<T> {
    Leaf {
        hash: Vec<u8>,
        value: T
    },

    Node {
        hash: Vec<u8>,
        left: Box<Tree<T>>,
        right: Box<Tree<T>>
    }
}

impl <T> Tree<T> where T: Hashable {

    fn new(hash: Vec<u8>, value: T) -> Self {
        Tree::Leaf {
            hash: hash,
            value: value
        }
    }

    fn get_hash(&self) -> &Vec<u8> {
        match *self {
            Tree::Leaf { ref hash, value: _ }          => hash,
            Tree::Node { ref hash, left: _, right: _ } => hash
        }
    }
}

fn make_leaf<D, T>(digest: &mut D, value: T) -> Tree<T> where D: Digest, T: Hashable {
    let hash = make_hash::<D, T>(digest, value.to_bytes());
    Tree::new(hash, value)
}

pub struct MerkleTree<D, T> where D: Digest, T: Hashable {
    digest: D,
    tree: Tree<T>
}

impl <D, T> MerkleTree<D, T> where D: Digest, T: Hashable {

    pub fn from_vec(mut digest: D, values: Vec<T>) -> Self {
        if values.is_empty() {
            panic!("Cannot build a Merkle tree from an empty vector.");
        }

        let len = values.len();
        let mut cur = Vec::with_capacity(len);

        for v in values {
            let leaf = make_leaf(&mut digest, v);
            cur.push(leaf);
        }

        cur.reverse();

        while cur.len() > 1 {
            let mut next = Vec::with_capacity(len);

            while cur.len() > 0 {
                if cur.len() == 1 {
                    next.push(cur.pop().unwrap());
                }
                else {
                    let right = cur.pop().unwrap();
                    let left  = cur.pop().unwrap();

                    let combined_hash = combine_hashes::<D>(
                        &mut digest,
                        left.get_hash().as_slice(),
                        right.get_hash().as_slice()
                    );

                    let node = Tree::Node {
                       hash: combined_hash,
                       left: Box::new(left),
                       right: Box::new(right)
                    };

                    next.push(node);
                }
            }

            cur = next;
        }

        let tree = cur.remove(0);

        MerkleTree {
            digest: digest,
            tree: tree
        }
    }

}

#[cfg(test)]
use crypto::sha3::Sha3;

#[test]
fn test_stuff() {
}

#[cfg(test)]
pub mod tests;
<|endoftext|>