<commit_before>//! This crate helps to create a Fractalide component
//!
//! It provides the macro `component` which takes the high level view of the component, and creates the code for the scheduler.
//!
//! It also declare the Trait Agent and the shared methods needed by every component and the scheduler.

extern crate capnp;

// TODO : Add method to remove components
use ports::{IPSender, IPReceiver};
use scheduler::Signal;
use result::Result;

/// Provide the generic functions of agents
///
/// These three functions are used by the scheduler
pub trait Agent {
    /// Return true if there is at least one input port
    fn is_input_ports(&self) -> bool;
    /// Connect output port
    fn connect(&mut self, port: &str, sender: IPSender) -> Result<()>;
    /// Connect array output port
    fn connect_array(&mut self, port: &str, element: String, sender: IPSender) -> Result<()>;
    /// Add input element
    fn add_inarr_element(&mut self, port: &str, element: String, recv: IPReceiver) -> Result<()>;
    /// Run the method of the component, his personal logic
    fn run(&mut self) -> Result<Signal>;
}

/// The agent macro.
///
/// It helps to define a agent, by defining the input and output ports, if there is an option or an acc port, ...
///
/// Example :
///
/// ```rust,ignore
/// agent! {
///    inputs(input: any),
///    outputs(output: any),
///    option(generic_text),
///    fn run(&mut self) -> Result<Signal> {
///        // Receive an IP
///        let ip = try!(self.input.input.recv());
///
///        // Received an IP from the option port (a generic_text)
///        let opt = self.recv_opt();
///
///        // Get the capn'p reader
///        let reader: generic_text::Reader = try!(opt.read_schema());
///        // Print the option
///        println!("{}", try!(reader.get_text()));
///
///        // Send the received IP outside, but don't care about the success (drop on fail)
///        let _ = self.output.output.send(ip);
///
///        Ok(End)
///    }
/// }
/// ```
#[macro_export]
macro_rules! agent {
    (
        $( input($( $input_name:ident: $input_contract:ident ),*), )*
        $( inarr($( $input_a_name:ident: $input_a_contract:ident ),*), )*
        $( output($( $output_name:ident: $output_contract:ident ),*), )*
        $( outarr($( $output_a_name:ident: $output_a_contract:ident ),*), )*
        $( portal( $portal_type:ty => $portal_value:expr ), )*
        $( option($option:ident), )*
        $( accumulator($acc:ident ), )*
        fn run(&mut $arg:ident) -> Result<Signal> $fun:block
    )
        =>
    {
        use rustfbp::agent::Agent;

        use rustfbp::result;
        use rustfbp::result::Result;
        use rustfbp::scheduler::{CompMsg, Signal};
        use std::error::Error;

        use std::sync::mpsc::{Sender};
        use std::sync::mpsc::channel;

        use rustfbp::ports::{IP, IPSender, IPReceiver, OutputSend};

        #[allow(unused_imports)]
        use std::collections::HashMap;

        use capnp::serialize;
        use capnp::message;

        use std::io::{Read, Write};

        use rustfbp::scheduler::Signal::*;

        mod edge_capnp {
                include!("edge_capnp.rs");
        }

        use edge_capnp::*;

        impl ThisAgent {
            $(
            fn dummy() {
                if stringify!($option) != "" {}
            }
            pub fn recv_option(&mut self) -> IP {
                self.try_recv_option();
                if self.option_ip.is_none() {
                    self.option_ip = self.input.option.recv().ok();
                }
                match self.option_ip {
                    Some(ref ip) => ip.clone(),
                    None => unreachable!(),
                }
            }

            pub fn try_recv_option(&mut self) -> Option<IP> {
                loop {
                    match self.input.option.try_recv() {
                        Err(_) => { break; },
                        Ok(ip) => { self.option_ip = Some(ip); }
                    };
                }
                self.option_ip.as_ref().map(|ip|{ ip.clone() })
            }
        }

        // simple and array

            fn get_ports(&mut self) -> &mut Ports {
                &mut self.ports
            }
        impl Agent for ThisAgent {

            fn is_input_ports(&self) -> bool {
                $(
                    if true || stringify!($input_field_name) == "" { return true; }
                )*
                $(
                    if true || stringify!($input_array_name) == "" { return true; }
                )*
                false
            }

            fn run(&mut $arg) -> Result<()> $fun
        pub struct Input {
            option: IPReceiver,
            acc: IPReceiver,
            $($(
                $input_name: IPReceiver,
            )*)*
        }

        pub struct Inarr {
            $($(
                $input_a_name: HashMap<String, IPReceiver>,
            )*)*
        }

        pub struct Output {
            acc: Option<IPSender>,
            $($(
                $output_name: Option<IPSender>,
            )*)*
        }

        pub struct Outarr {
            $($(
                $output_a_name: HashMap<String, IPSender>
            )*)*
        }

        /* Global component */

        #[allow(dead_code)]
        #[allow(non_camel_case_types)]
        pub struct ThisAgent {
            name: String,
            pub input: Input,
            pub inarr: Inarr,
            pub output: Output,
            pub outarr: Outarr,
            pub option_ip: Option<IP>,
            sched: Sender<CompMsg>,
            $(
            pub portal: $portal_type ,
            )*
        }

        #[allow(dead_code)]
        pub fn new(name: String, sched: Sender<CompMsg>) -> Result<(Box<Agent + Send>, HashMap<String, IPSender>)> {
            let (ports, senders) = try!(Ports::new(name.clone(), sched,
                                   vec!["option".into(), "acc".into(), $( stringify!($input_field_name).to_string() ),*],
                                   vec![$( stringify!($input_array_name).to_string() ),*],
                                   vec!["acc".into(), $( stringify!($output_field_name).to_string() ),*],
                                   vec![$( stringify!($output_array_name).to_string() ),*],));

            // Put it together
            let comp = $name{
                name: name,
                ports: ports,
                option_ip: None,
                $(
                    portal: $portal_value,
                )*
            };
            Ok((Box::new(comp) as Box<Agent + Send>, senders))
        }

        #[no_mangle]
        pub extern fn create_agent(name: String, sched: Sender<CompMsg>) -> Result<(Box<Agent + Send>, HashMap<String, IPSender>)> {
            new(name, sched)
        }

        #[no_mangle]
        pub extern fn get_schema_input(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($input_field_name)=> Ok(stringify!($input_edge_name).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_input_array(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($input_array_name) => Ok(stringify!($input_edge_array).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_output(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($output_field_name)=> Ok(stringify!($output_edge_name).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_output_array(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($output_array_name) => Ok(stringify!($output_edge_array).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }
    }
}
<commit_msg>Agent: implementation of the new agent<commit_after>//! This crate helps to create a Fractalide component
//!
//! It provides the macro `component` which takes the high level view of the component, and creates the code for the scheduler.
//!
//! It also declare the Trait Agent and the shared methods needed by every component and the scheduler.

extern crate capnp;

// TODO : Add method to remove components
use ports::{IPSender, IPReceiver};
use scheduler::Signal;
use result::Result;

/// Provide the generic functions of agents
///
/// These three functions are used by the scheduler
pub trait Agent {
    /// Return true if there is at least one input port
    fn is_input_ports(&self) -> bool;
    /// Connect output port
    fn connect(&mut self, port: &str, sender: IPSender) -> Result<()>;
    /// Connect array output port
    fn connect_array(&mut self, port: &str, element: String, sender: IPSender) -> Result<()>;
    /// Add input element
    fn add_inarr_element(&mut self, port: &str, element: String, recv: IPReceiver) -> Result<()>;
    /// Run the method of the component, his personal logic
    fn run(&mut self) -> Result<Signal>;
}

/// The agent macro.
///
/// It helps to define a agent, by defining the input and output ports, if there is an option or an acc port, ...
///
/// Example :
///
/// ```rust,ignore
/// agent! {
///    inputs(input: any),
///    outputs(output: any),
///    option(generic_text),
///    fn run(&mut self) -> Result<Signal> {
///        // Receive an IP
///        let ip = try!(self.input.input.recv());
///
///        // Received an IP from the option port (a generic_text)
///        let opt = self.recv_opt();
///
///        // Get the capn'p reader
///        let reader: generic_text::Reader = try!(opt.read_schema());
///        // Print the option
///        println!("{}", try!(reader.get_text()));
///
///        // Send the received IP outside, but don't care about the success (drop on fail)
///        let _ = self.output.output.send(ip);
///
///        Ok(End)
///    }
/// }
/// ```
#[macro_export]
macro_rules! agent {
    (
        $( input($( $input_name:ident: $input_contract:ident ),*), )*
        $( inarr($( $input_a_name:ident: $input_a_contract:ident ),*), )*
        $( output($( $output_name:ident: $output_contract:ident ),*), )*
        $( outarr($( $output_a_name:ident: $output_a_contract:ident ),*), )*
        $( portal( $portal_type:ty => $portal_value:expr ), )*
        $( option($option:ident), )*
        $( accumulator($acc:ident ), )*
        fn run(&mut $arg:ident) -> Result<Signal> $fun:block
    )
        =>
    {
        use rustfbp::agent::Agent;

        use rustfbp::result;
        use rustfbp::result::Result;
        use rustfbp::scheduler::{CompMsg, Signal};
        use std::error::Error;

        use std::sync::mpsc::{Sender};
        use std::sync::mpsc::channel;

        use rustfbp::ports::{IP, IPSender, IPReceiver, OutputSend};

        #[allow(unused_imports)]
        use std::collections::HashMap;

        use capnp::serialize;
        use capnp::message;

        use std::io::{Read, Write};

        use rustfbp::scheduler::Signal::*;

        mod edge_capnp {
                include!("edge_capnp.rs");
        }

        use edge_capnp::*;

        impl ThisAgent {
            $(
            fn dummy() {
                if stringify!($option) != "" {}
            }
            pub fn recv_option(&mut self) -> IP {
                self.try_recv_option();
                if self.option_ip.is_none() {
                    self.option_ip = self.input.option.recv().ok();
                }
                match self.option_ip {
                    Some(ref ip) => ip.clone(),
                    None => unreachable!(),
                }
            }

            pub fn try_recv_option(&mut self) -> Option<IP> {
                loop {
                    match self.input.option.try_recv() {
                        Err(_) => { break; },
                        Ok(ip) => { self.option_ip = Some(ip); }
                    };
                }
                self.option_ip.as_ref().map(|ip|{ ip.clone() })
            }
            )*

            pub fn send_action(&mut self, output: &str, ip: IP) -> Result<()> {
                if let Some(sender) = {
                    match output {
                        $($(
                            stringify!($output_a_name) =>  { self.outarr.$output_a_name.get(&ip.action) }
                        )*)*
                            _ => None
                    }
                } // End of the if let Some = { ... }
                {
                    let s: &IPSender = sender;
                    try!(s.send(ip));
                }
                else {
                    match output {
                        $($(
                            stringify!($output_name) => { self.output.$output_name.send(ip);}
                        )*)*
                            _ => { return Err(result::Error::PortDontExist(output.into())); }
                    }
                }
                Ok(())
            }
        }

        impl Agent for ThisAgent {

            fn is_input_ports(&self) -> bool {
                $($(
                    if true || stringify!($input_name) == "" { return true; }
                )*)*
                $($(
                    if true || stringify!($input_a_name) == "" { return true; }
                )*)*
                false
            }

            fn connect(&mut self, port: &str, sender: IPSender) -> Result<()> {
                match port {
                    $($(
                        stringify!($output_name) => {
                            self.output.$output_name = Some(sender);
                        }
                    )*)*
                        _ => {
                            return Err(result::Error::PortDontExist(port.into()));
                        }
                }
                Ok(())
            }

            fn connect_array(&mut self, port: &str, element: String, sender: IPSender) -> Result<()> {
                match port {
                    $($(
                        stringify!($output_a_name) => {
                            self.outarr.$output_a_name.insert(element, sender);
                        }
                    )*)*
                        _ => {
                            return Err(result::Error::PortDontExist(port.into()));
                        }
                }
                Ok(())
            }

            fn add_inarr_element(&mut self, port: &str, element: String, recv: IPReceiver) -> Result<()> {
                match port {
                    $($(
                        stringify!($input_a_name) => {
                            self.inarr.$input_a_name.insert(element, recv);
                            Ok(())
                        }
                    )*)*
                        _ => {
                            Err(result::Error::PortDontExist(port.into()))
                        }
                }
            }

            fn run(&mut $arg) -> Result<Signal> $fun

        }

        pub struct Input {
            option: IPReceiver,
            acc: IPReceiver,
            $($(
                $input_name: IPReceiver,
            )*)*
        }

        pub struct Inarr {
            $($(
                $input_a_name: HashMap<String, IPReceiver>,
            )*)*
        }

        pub struct Output {
            acc: Option<IPSender>,
            $($(
                $output_name: Option<IPSender>,
            )*)*
        }

        pub struct Outarr {
            $($(
                $output_a_name: HashMap<String, IPSender>
            )*)*
        }

        /* Global component */

        #[allow(dead_code)]
        #[allow(non_camel_case_types)]
        pub struct ThisAgent {
            name: String,
            pub input: Input,
            pub inarr: Inarr,
            pub output: Output,
            pub outarr: Outarr,
            pub option_ip: Option<IP>,
            sched: Sender<CompMsg>,
            $(
            pub portal: $portal_type ,
            )*
        }

        #[allow(dead_code)]
        pub fn new(name: String, sched: Sender<CompMsg>) -> Result<(Box<Agent + Send>, HashMap<String, IPSender>)> {

            let mut senders: HashMap<String, IPSender> = HashMap::new();
            let option = IPReceiver::new(name.clone(), sched.clone(), false);
            senders.insert("option".to_string(), option.1);
            let acc = IPReceiver::new(name.clone(), sched.clone(), false);
            senders.insert("acc".to_string(), acc.1.clone());
            $($(
                let $input_name = IPReceiver::new(name.clone(), sched.clone(), true);
                senders.insert(stringify!($input_name).to_string(), $input_name.1);
            )*)*
            let input = Input {
                option: option.0,
                acc: acc.0,
                $($(
                    $input_name: $input_name.0,
                )*)*
            };

            let inarr = Inarr {
                $($(
                    $input_a_name: HashMap::new(),
                )*)*
            };

            let output = Output {
                acc: Some(acc.1),
                $($(
                    $output_name: None,
                )*)*
            };

            let outarr = Outarr {
                $($(
                    $output_a_name: HashMap::new(),
                )*)*
            };

            let agent= ThisAgent {
                name: name,
                input: input,
                inarr: inarr,
                output: output,
                outarr: outarr,
                option_ip: None,
                sched: sched,
                $(
                    portal: $portal_value,
                )*
            };

            Ok((Box::new(agent) as Box<Agent + Send>, senders))
        }

        #[no_mangle]
        pub extern fn create_agent(name: String, sched: Sender<CompMsg>) -> Result<(Box<Agent + Send>, HashMap<String, IPSender>)> {
            new(name, sched)
        }

        #[no_mangle]
        pub extern fn get_schema_input(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($input_field_name)=> Ok(stringify!($input_edge_name).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_input_array(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($input_array_name) => Ok(stringify!($input_edge_array).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_output(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($output_field_name)=> Ok(stringify!($output_edge_name).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_output_array(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($output_array_name) => Ok(stringify!($output_edge_array).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Integration with Musashi
extern crate libc;

// Register enum copied from Musashi's m68k_register_t enum
#[repr(C)]
#[derive(Copy, Clone)]
pub enum Register {
	/* Real registers */
	D0,		/* Data registers */
	D1,
	D2,
	D3,
	D4,
	D5,
	D6,
	D7,
	A0,		/* Address registers */
	A1,
	A2,
	A3,
	A4,
	A5,
	A6,
	A7,
	PC,		/* Program Counter */
	SR,		/* Status Register */
	SP,		/* The current Stack Pointer (located in A7) */
	USP,		/* User Stack Pointer */
	ISP,		/* Interrupt Stack Pointer */
	MSP,		/* Master Stack Pointer */
	SFC,		/* Source Function Code */
	DFC,		/* Destination Function Code */
	VBR,		/* Vector Base Register */
	CACR,		/* Cache Control Register */
	CAAR,		/* Cache Address Register */

	/* Assumed registers */
	/* These are cheat registers which emulate the 1-longword prefetch
	 * present in the 68000 and 68010.
	 */
	PrefAddr,	/* Last prefetch address */
	PrefData,	/* Last prefetch data */

	/* Convenience registers */
	PPC,		/* Previous value in the program counter */
	IR,			/* Instruction register */
	CpuType	/* Type of CPU being run */
}

#[repr(C)]
#[derive(Copy, Clone)]
enum CpuType
{
	Invalid,
	M68000,
	M68010,
	M68EC020,
	M68020,
	M68030,		/* Supported by disassembler ONLY */
	M68040		/* Supported by disassembler ONLY */
}

#[link(name = "musashi", kind = "static")]
extern {
	fn m68k_init();
	fn m68k_set_cpu_type(cputype: CpuType);
	fn m68k_pulse_reset();
	fn m68k_execute(num_cycles: i32) -> i32;
	fn m68k_get_reg(context: *mut libc::c_void, regnum: Register) -> u32;
	fn m68k_set_reg(regnum: Register, value: u32);
}
#[derive(Copy, Clone, Debug, PartialEq)]
enum Operation {
	None,
    ReadByte(u32),
    ReadWord(u32),
    ReadLong(u32),
    WriteByte(u32, u32),
    WriteWord(u32, u32),
    WriteLong(u32, u32),
}
static mut musashi_memory:  [u8; 1024] = [0u8; 1024];
// as statics are not allowed to have destructors, allocate a
// big enough array to hold the small number of operations
// expected from executing a very limited number of opcodes
static mut musashi_opcount: usize = 0;
static mut musashi_ops: [Operation; 128] = [Operation::None; 128];

unsafe fn register_op(op: Operation) {
	if(musashi_opcount < musashi_ops.len()) {
		musashi_ops[musashi_opcount] = op;
		musashi_opcount += 1;
	}
}
// callbacks from Musashi
#[no_mangle]
pub extern fn cpu_read_byte(address: u32) -> u32 {
	let op = Operation::ReadByte(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address] as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_word(address: u32) -> u32 {
	let op = Operation::ReadWord(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		((musashi_memory[address+0] as u32) << 8
		|(musashi_memory[address+1] as u32) << 0) as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_long(address: u32) -> u32 {
	let op = Operation::ReadLong(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		((musashi_memory[address+0] as u32) << 24
		|(musashi_memory[address+1] as u32) << 16
		|(musashi_memory[address+2] as u32) <<  8
		|(musashi_memory[address+3] as u32) <<  0) as u32
	}
}

#[no_mangle]
pub extern fn cpu_write_byte(address: u32, value: u32) {
	let op = Operation::WriteByte(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_word(address: u32, value: u32) {
	let op = Operation::WriteWord(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff00 >> 8) as u8;
		musashi_memory[address+1] = (value & 0x00ff >> 0) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_long(address: u32, value: u32) {
	let op = Operation::WriteLong(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff000000 >> 24) as u8;
		musashi_memory[address+1] = (value & 0x00ff0000 >> 16) as u8;
		musashi_memory[address+2] = (value & 0x0000ff00 >>  8) as u8;
		musashi_memory[address+3] = (value & 0x000000ff >>  0) as u8;
	}
}

#[no_mangle]
pub extern fn cpu_pulse_reset() {panic!("pr")}
#[no_mangle]
pub extern fn cpu_long_branch() {}
#[no_mangle]
pub extern fn cpu_set_fc(fc: u32) {
	//println!("set_fc {}", fc)
}
#[no_mangle]
pub extern fn cpu_irq_ack(level: i32) -> i32 {panic!("ia")}
#[no_mangle]
pub extern fn cpu_instr_callback() {}

use std::ptr;

pub fn experimental_communication() {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(Register::D0, 123);
		println!("D0: {}", m68k_get_reg(ptr::null_mut(), Register::D0));
	}
}

pub fn roundtrip_register(reg: Register, value: u32) -> u32 {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(reg, value);
		m68k_get_reg(ptr::null_mut(), reg)
	}
}

use cpu::Core;

pub fn roundtrip_core(core: &mut Core) {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		let regs = [Register::D0, Register::D1, Register::D2, Register::D3, Register::D4, Register::D5, Register::D6, Register::D7, Register::A0, Register::A1, Register::A2, Register::A3, Register::A4, Register::A5, Register::A6, Register::A7];
		for (i, &reg) in regs.iter().enumerate() {m68k_set_reg(reg, core.dar[i]);}
		m68k_set_reg(Register::PC, core.pc);
		m68k_set_reg(Register::SP, core.sp);
		m68k_set_reg(Register::SR, core.status_register());

		m68k_execute(1);

		for (i, &reg) in regs.iter().enumerate() {
			core.dar[i] = m68k_get_reg(ptr::null_mut(), reg);
		}
		core.pc = m68k_get_reg(ptr::null_mut(), Register::PC);
		core.sp = m68k_get_reg(ptr::null_mut(), Register::SP);
		core.sr_to_flags(m68k_get_reg(ptr::null_mut(), Register::SR));
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use super::musashi_memory;
	use cpu::Core;

	#[test]
	fn roundtrip_d0() {
		assert_eq!(256, roundtrip_register(Register::D0, 256));
	}

	#[test]
	fn roundtrip_abcd_rr() {
		let mut cpu = Core::new_mem(0x40, &[0xc3, 0x00]);
		unsafe {
			let offset = cpu.pc as usize;
			for (i,b) in cpu.mem.iter().enumerate() {
				musashi_memory[i] = *b;
			}
		}
		cpu.dar[0] = 0x16;
		cpu.dar[1] = 0x26;
		roundtrip_core(&mut cpu);

		// 16 + 26 is 42
		assert_eq!(0x42, cpu.dar[1]);
	}
}<commit_msg>Improve single step execution and roundtrip tests<commit_after>// Integration with Musashi
extern crate libc;

// Register enum copied from Musashi's m68k_register_t enum
#[repr(C)]
#[derive(Copy, Clone)]
pub enum Register {
	/* Real registers */
	D0,		/* Data registers */
	D1,
	D2,
	D3,
	D4,
	D5,
	D6,
	D7,
	A0,		/* Address registers */
	A1,
	A2,
	A3,
	A4,
	A5,
	A6,
	A7,
	PC,		/* Program Counter */
	SR,		/* Status Register */
	SP,		/* The current Stack Pointer (located in A7) */
	USP,		/* User Stack Pointer */
	ISP,		/* Interrupt Stack Pointer */
	MSP,		/* Master Stack Pointer */
	SFC,		/* Source Function Code */
	DFC,		/* Destination Function Code */
	VBR,		/* Vector Base Register */
	CACR,		/* Cache Control Register */
	CAAR,		/* Cache Address Register */

	/* Assumed registers */
	/* These are cheat registers which emulate the 1-longword prefetch
	 * present in the 68000 and 68010.
	 */
	PrefAddr,	/* Last prefetch address */
	PrefData,	/* Last prefetch data */

	/* Convenience registers */
	PPC,		/* Previous value in the program counter */
	IR,			/* Instruction register */
	CpuType	/* Type of CPU being run */
}

#[repr(C)]
#[derive(Copy, Clone)]
enum CpuType
{
	Invalid,
	M68000,
	M68010,
	M68EC020,
	M68020,
	M68030,		/* Supported by disassembler ONLY */
	M68040		/* Supported by disassembler ONLY */
}

#[link(name = "musashi", kind = "static")]
extern {
	fn m68k_init();
	fn m68k_set_cpu_type(cputype: CpuType);
	fn m68k_pulse_reset();
	fn m68k_execute(num_cycles: i32) -> i32;
	fn m68k_get_reg(context: *mut libc::c_void, regnum: Register) -> u32;
	fn m68k_set_reg(regnum: Register, value: u32);
}
#[derive(Copy, Clone, Debug, PartialEq)]
enum Operation {
	None,
    ReadByte(u32),
    ReadWord(u32),
    ReadLong(u32),
    WriteByte(u32, u32),
    WriteWord(u32, u32),
    WriteLong(u32, u32),
}
static mut musashi_memory:  [u8; 1024] = [0u8; 1024];
// as statics are not allowed to have destructors, allocate a
// big enough array to hold the small number of operations
// expected from executing a very limited number of opcodes
static mut musashi_opcount: usize = 0;
static mut musashi_ops: [Operation; 128] = [Operation::None; 128];

unsafe fn register_op(op: Operation) {
	if(musashi_opcount < musashi_ops.len()) {
		musashi_ops[musashi_opcount] = op;
		musashi_opcount += 1;
	}
}
// callbacks from Musashi
#[no_mangle]
pub extern fn cpu_read_byte(address: u32) -> u32 {
	let op = Operation::ReadByte(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address] as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_word(address: u32) -> u32 {
	let op = Operation::ReadWord(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		((musashi_memory[address+0] as u32) << 8
		|(musashi_memory[address+1] as u32) << 0) as u32
	}
}
#[no_mangle]
pub extern fn cpu_read_long(address: u32) -> u32 {
	let op = Operation::ReadLong(address);
	let address = address as usize;
	unsafe {
		register_op(op);
		((musashi_memory[address+0] as u32) << 24
		|(musashi_memory[address+1] as u32) << 16
		|(musashi_memory[address+2] as u32) <<  8
		|(musashi_memory[address+3] as u32) <<  0) as u32
	}
}

#[no_mangle]
pub extern fn cpu_write_byte(address: u32, value: u32) {
	let op = Operation::WriteByte(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_word(address: u32, value: u32) {
	let op = Operation::WriteWord(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff00 >> 8) as u8;
		musashi_memory[address+1] = (value & 0x00ff >> 0) as u8;
	}
}
#[no_mangle]
pub extern fn cpu_write_long(address: u32, value: u32) {
	let op = Operation::WriteLong(address, value);
	let address = address as usize;
	unsafe {
		register_op(op);
		musashi_memory[address+0] = (value & 0xff000000 >> 24) as u8;
		musashi_memory[address+1] = (value & 0x00ff0000 >> 16) as u8;
		musashi_memory[address+2] = (value & 0x0000ff00 >>  8) as u8;
		musashi_memory[address+3] = (value & 0x000000ff >>  0) as u8;
	}
}

#[no_mangle]
pub extern fn cpu_pulse_reset() {panic!("pr")}
#[no_mangle]
pub extern fn cpu_long_branch() {}
#[no_mangle]
pub extern fn cpu_set_fc(fc: u32) {
	//println!("set_fc {}", fc)
}
#[no_mangle]
pub extern fn cpu_irq_ack(level: i32) -> i32 {panic!("ia")}
#[no_mangle]
pub extern fn cpu_instr_callback() {}

use std::ptr;

pub fn experimental_communication() {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(Register::D0, 123);
		println!("D0: {}", m68k_get_reg(ptr::null_mut(), Register::D0));
	}
}

pub fn roundtrip_register(reg: Register, value: u32) -> u32 {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		m68k_set_reg(reg, value);
		m68k_get_reg(ptr::null_mut(), reg)
	}
}

use cpu::Core;

pub fn execute1(core: &mut Core) {
	unsafe {
		m68k_init();
		m68k_set_cpu_type(CpuType::M68000);
		// m68k_pulse_reset(); causes irrelevant reads from 0x00000000 to set PC/SP, a jump to PC,
		// and resetting of state, which is unneeded because we override that state anyway
		let regs = [Register::D0, Register::D1, Register::D2, Register::D3, Register::D4, Register::D5, Register::D6, Register::D7, Register::A0, Register::A1, Register::A2, Register::A3, Register::A4, Register::A5, Register::A6, Register::A7];
		for (i, &reg) in regs.iter().enumerate() {m68k_set_reg(reg, core.dar[i]);}
		m68k_set_reg(Register::PC, core.pc);
		m68k_set_reg(Register::SP, core.sp);
		m68k_set_reg(Register::SR, core.status_register());
		unsafe {
			for (i,b) in core.mem.iter().enumerate() {
				musashi_memory[i] = *b;
			}
		}
		m68k_execute(1);

		for (i, &reg) in regs.iter().enumerate() {
			core.dar[i] = m68k_get_reg(ptr::null_mut(), reg);
		}
		core.pc = m68k_get_reg(ptr::null_mut(), Register::PC);
		core.sp = m68k_get_reg(ptr::null_mut(), Register::SP);
		core.sr_to_flags(m68k_get_reg(ptr::null_mut(), Register::SR));
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use super::musashi_memory;
	use super::musashi_ops;
	use super::musashi_opcount;
	use super::Operation;
	use cpu::Core;

	fn get_ops() -> Vec<Operation> {
		let mut res: Vec<Operation> = vec![];
		unsafe {
			for i in 0..musashi_opcount {
				res.push(musashi_ops[i]);
			}
		}
		res
	}
	#[test]
	fn roundtrip_d0() {
		assert_eq!(256, roundtrip_register(Register::D0, 256));
	}

	#[test]
	fn roundtrip_abcd_rr() {
		let pc = 0x40;
		let mut cpu = Core::new_mem(pc, &[0xc3, 0x00]);
		cpu.dar[0] = 0x16;
		cpu.dar[1] = 0x26;
		execute1(&mut cpu);

		// 16 + 26 is 42
		assert_eq!(0x42, cpu.dar[1]);

		let ops = get_ops();
		assert_eq!(1, ops.len());
		assert_eq!(Operation::ReadLong(pc), ops[0]);
	}
}<|endoftext|>


<commit_before>//! Networking primitives for Uni.rs

use cell::GlobalCell;

use thread::Scheduler;

mod imp;

mod pkt;
mod intf;
pub mod conn;

mod eth;

pub mod defs;

pub use self::imp::{Instance, InstanceWeak};

pub use self::pkt::{
    Packet,
    Builder as PacketBuilder,
    Formatter as PacketFormatter,
};

pub use self::intf::{Interface, InterfaceWeak, InterfaceRaw, V4Configuration};

static STACK: GlobalCell<Instance> = GlobalCell::new();

/// Uni.rs network stack
pub struct Stack;

impl Stack {
    #[doc(hidden)]
    pub fn init() {
        STACK.set(Instance::new());

        // Spawn the network thread
        Scheduler::spawn(|| {
            Instance::network_thread(STACK.as_ref().clone());
        });
    }

    /// Returns interfaces registered in the network stack
    pub fn instance() -> Instance {
        STACK.as_ref().clone()
    }
}
<commit_msg>net: Reexport UniConn and MultiConn in net::<commit_after>//! Networking primitives for Uni.rs

use cell::GlobalCell;

use thread::Scheduler;

mod imp;

mod pkt;
mod intf;
pub mod conn;

mod eth;

pub mod defs;

pub use self::imp::{Instance, InstanceWeak};

pub use self::pkt::{
    Packet,
    Builder as PacketBuilder,
    Formatter as PacketFormatter,
};

pub use self::intf::{Interface, InterfaceWeak, InterfaceRaw, V4Configuration};

pub use self::conn::{UniConn, MultiConn};

static STACK: GlobalCell<Instance> = GlobalCell::new();

/// Uni.rs network stack
pub struct Stack;

impl Stack {
    #[doc(hidden)]
    pub fn init() {
        STACK.set(Instance::new());

        // Spawn the network thread
        Scheduler::spawn(|| {
            Instance::network_thread(STACK.as_ref().clone());
        });
    }

    /// Returns interfaces registered in the network stack
    pub fn instance() -> Instance {
        STACK.as_ref().clone()
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2015 Rustcc Developers

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::ops::{Deref, DerefMut};
use std::io;
use std::net::{ToSocketAddrs, SocketAddr};

use mio::Interest;
use mio::buf::{Buf, MutBuf, SliceBuf, MutSliceBuf};

use processor::Processor;

pub struct UdpSocket(::mio::udp::UdpSocket);

impl UdpSocket {
    /// Returns a new, unbound, non-blocking, IPv4 UDP socket
    pub fn v4() -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(::mio::udp::UdpSocket::v4())))
    }

    /// Returns a new, unbound, non-blocking, IPv6 UDP socket
    pub fn v6() -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(::mio::udp::UdpSocket::v6())))
    }

    pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
        super::each_addr(addr, |a| {
            ::mio::udp::UdpSocket::bound(&a)
        }).map(UdpSocket)
    }

    pub fn try_clone(&self) -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(self.0.try_clone())))
    }

    pub fn send_to<A: ToSocketAddrs>(&self, slice_buf: &[u8], target: A) -> io::Result<usize> {
        let mut buf = SliceBuf::wrap(slice_buf);

        let mut last_err = Ok(0);
        for addr in try!(target.to_socket_addrs()) {
            match self.0.send_to(&mut buf, &addr) {
                Ok(None) => {
                    debug!("UdpSocket send_to WOULDBLOCK");
                    break;
                },
                Ok(Some(..)) => {
                    return Ok(slice_buf.len() - buf.remaining());
                },
                Err(err) => last_err = Err(err),
            }
        }

        if last_err.is_err() {
            return last_err;
        }

        for addr in try!(target.to_socket_addrs()) {
            loop {
                try!(Processor::current().wait_event(&self.0, Interest::writable()));

                match self.0.send_to(&mut buf, &addr) {
                    Ok(None) => {
                        warn!("UdpSocket send_to WOULDBLOCK");
                    },
                    Ok(Some(..)) => {
                        return Ok(slice_buf.len() - buf.remaining());
                    },
                    Err(err) => {
                        last_err = Err(err);
                        break;
                    }
                }
            }
        }

        last_err
    }

    pub fn recv_from(&self, slice_buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
        let total_len = slice_buf.len();
        let mut buf = MutSliceBuf::wrap(slice_buf);

        match try!(self.0.recv_from(&mut buf)) {
            None => {
                debug!("UdpSocket recv_from WOULDBLOCK");
            },
            Some(addr) => {
                return Ok((total_len - buf.remaining(), addr));
            }
        }

        loop {
            try!(Processor::current().wait_event(&self.0, Interest::readable()));

            match try!(self.0.recv_from(&mut buf)) {
                None => {
                    warn!("UdpSocket recv_from WOULDBLOCK");
                },
                Some(addr) => {
                    return Ok((total_len - buf.remaining(), addr));
                }
            }
        }
    }
}

impl Deref for UdpSocket {
    type Target = ::mio::udp::UdpSocket;

    fn deref(&self) -> &::mio::udp::UdpSocket {
        return &self.0
    }
}

impl DerefMut for UdpSocket {
    fn deref_mut(&mut self) -> &mut ::mio::udp::UdpSocket {
        return &mut self.0
    }
}
<commit_msg>fixed bug in udp<commit_after>// The MIT License (MIT)

// Copyright (c) 2015 Rustcc Developers

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::ops::{Deref, DerefMut};
use std::io;
use std::net::{ToSocketAddrs, SocketAddr};

use mio::Interest;
use mio::buf::{Buf, MutBuf, SliceBuf, MutSliceBuf};

use processor::Processor;

pub struct UdpSocket(::mio::udp::UdpSocket);

impl UdpSocket {
    /// Returns a new, unbound, non-blocking, IPv4 UDP socket
    pub fn v4() -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(::mio::udp::UdpSocket::v4())))
    }

    /// Returns a new, unbound, non-blocking, IPv6 UDP socket
    pub fn v6() -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(::mio::udp::UdpSocket::v6())))
    }

    pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> {
        super::each_addr(addr, |a| {
            ::mio::udp::UdpSocket::bound(&a)
        }).map(UdpSocket)
    }

    pub fn try_clone(&self) -> io::Result<UdpSocket> {
        Ok(UdpSocket(try!(self.0.try_clone())))
    }

    pub fn send_to<A: ToSocketAddrs>(&self, slice_buf: &[u8], target: A) -> io::Result<usize> {
        let mut buf = SliceBuf::wrap(slice_buf);

        let mut last_err = Ok(0);
        for addr in try!(target.to_socket_addrs()) {
            match self.0.send_to(&mut buf, &addr) {
                Ok(None) => {
                    debug!("UdpSocket send_to WOULDBLOCK");

                    loop {
                        try!(Processor::current().wait_event(&self.0, Interest::writable()));

                        match self.0.send_to(&mut buf, &addr) {
                            Ok(None) => {
                                warn!("UdpSocket send_to WOULDBLOCK");
                            },
                            Ok(Some(..)) => {
                                return Ok(slice_buf.len() - buf.remaining());
                            },
                            Err(err) => {
                                return Err(err);
                            }
                        }
                    }
                },
                Ok(Some(..)) => {
                    return Ok(slice_buf.len() - buf.remaining());
                },
                Err(err) => last_err = Err(err),
            }
        }

        last_err
    }

    pub fn recv_from(&self, slice_buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
        let total_len = slice_buf.len();
        let mut buf = MutSliceBuf::wrap(slice_buf);

        match try!(self.0.recv_from(&mut buf)) {
            None => {
                debug!("UdpSocket recv_from WOULDBLOCK");
            },
            Some(addr) => {
                return Ok((total_len - buf.remaining(), addr));
            }
        }

        loop {
            try!(Processor::current().wait_event(&self.0, Interest::readable()));

            match try!(self.0.recv_from(&mut buf)) {
                None => {
                    warn!("UdpSocket recv_from WOULDBLOCK");
                },
                Some(addr) => {
                    return Ok((total_len - buf.remaining(), addr));
                }
            }
        }
    }
}

impl Deref for UdpSocket {
    type Target = ::mio::udp::UdpSocket;

    fn deref(&self) -> &::mio::udp::UdpSocket {
        return &self.0
    }
}

impl DerefMut for UdpSocket {
    fn deref_mut(&mut self) -> &mut ::mio::udp::UdpSocket {
        return &mut self.0
    }
}
<|endoftext|>


<commit_before>//! The neural network struct. See the module level documentation for usage.

use std::ops::Range;
use std::io;

use utils::Stack;
use file;
use gene::*;
use gene::GeneExtras::*;

const BIAS_GENE_VALUE: f64 = 1.0;

#[derive(Clone, Debug, PartialEq)]
pub struct Network {
    // size should be the length of the genome minus one, don't forget
    pub size: usize,
    pub genome: Vec<Gene>
}

impl Network {
    /// Evaluates the neural network with the given inputs, returning a vector of outputs. The encoding can
    /// encode recurrent connections and bias inputs, so an internal state is used. It is important to run
    /// the clear_state method before calling evaluate again, unless it is desired to allow data
    /// carry over from the previous evaluation, for example if the network is being used as a real
    /// time controller.
    ///
    /// If too little inputs are given, the empty inputs will have a value of zero. If too many
    /// inputs are given, the extras are discarded.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use cge::Network;
    ///
    /// // Load a neural network
    /// let mut network = Network::load_from_file("neural_network.ann").unwrap();
    ///
    /// // Get the output of the neural network the the specified inputs
    /// let result = network.evaluate(&vec![1.0, 1.0]);
    ///
    /// // Get the output of the neural network with no inputs
    /// let result = network.evaluate(&Vec::new());
    ///
    /// // Get the output of the neural network with too many inputs (extras aren't used)
    /// let result = network.evaluate(&vec![1.0, 1.0, 1.0]);
    ///
    /// // Let's say adder.ann is a file with a neural network with recurrent connections, used for
    /// // adding numbers together.
    /// let mut adder = Network::load_from_file("adder.ann").unwrap();
    ///
    /// // result_one will be 1.0
    /// let result_one = adder.evaluate(&vec![1.0]);
    ///
    /// // result_two will be 3.0
    /// let result_two = adder.evaluate(&vec![2.0]);
    ///
    /// // result_three will be 5.0
    /// let result_three = adder.evaluate(&vec![2.0]);
    ///
    /// // If this behavior is not desired, call the clear_state method between evaluations:
    /// let result_one = adder.evaluate(&vec![1.0]);
    ///
    /// adder.clear_state();
    ///
    /// // The 1.0 from the previous call is gone, so result_two will be 2.0
    /// let result_two = adder.evaluate(&vec![2.0]);
    /// ```
    pub fn evaluate(&mut self, inputs: &Vec<f64>) -> Vec<f64> {
        // Set inputs
        for gene in &mut self.genome {
            if let Input(ref mut current_value) = gene.variant {
                *current_value = match inputs.get(gene.id) {
                    Some(v) => *v,
                    None => 0.0
                }
            }
        }

        let size = self.size;
        self.evaluate_slice(0..size, true)
    }

    /// Clears the internal state of the neural network.
    pub fn clear_state(&mut self) {
        for gene in &mut self.genome {
            match gene.variant {
                Input(ref mut current_value) => {
                    *current_value = 0.0;
                },
                Neuron(ref mut current_value, _) => {
                    *current_value = 0.0;
                }
                _ => {}
            }
        }
    }

    /// Saves the neural network to a file. Returns an empty tuple on success, or an io error.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use cge::Network;
    ///
    /// // Create a neural network
    /// let network = Network {
    ///     size: 0,
    ///     genome: Vec::new()
    /// };
    ///
    /// // Save network to neural_network.ann
    /// network.save_to_file("neural_network.ann");
    /// ```
    pub fn save_to_file(&self, path: &str) -> io::Result<()> {
        file::write_network(self, path)
    }

    /// Loads a neural network from a file. No guarantees are made about the validity of the
    /// genome. Returns the network, or an io error. If the file is in a bad format,
    /// io::ErrorKind::InvalidData is returned.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use cge::Network;
    ///
    /// // Loads a network from the file neural_network.ann
    /// let mut network = Network::load_from_file("neural_network.ann").unwrap();
    /// ```
    pub fn load_from_file(path: &str) -> io::Result<Network> {
        file::read_network(path)
    }

    // Returns the output of sub-linear genome in the given range
    fn evaluate_slice(&mut self, range: Range<usize>, neuron_update: bool) -> Vec<f64> {
        let mut gene_index = range.end;
        // Initialize a stack for evaluating the neural network
        let mut stack = Stack::new();

        // Iterate backwards over the specified slice
        while gene_index >= range.start {
            let variant = self.genome[gene_index].variant.clone();

            // For debugging: uncomment these print statements
            // Perhaps add it as an option to help users
            // println!("{:?}", variant);

            match variant {
                Input(_) => {
                    // If the gene is an input, push its value multiplied by the inputs weight onto
                    // the stack
                    let (weight, _, value) = self.genome[gene_index].ref_input().unwrap();
                    stack.push(weight * value);
                },
                Neuron(_, _) => {
                    // If the gene is a neuron, pop a number (the neurons input count) of inputs
                    // off the stack, and push their sum multiplied by the neurons weight onto the
                    // stack
                    let (weight, _, value, inputs) = self.genome[gene_index].ref_mut_neuron().unwrap();
                    let new_value = stack.pop(*inputs).unwrap().iter().fold(0.0, |acc, i| acc + i);

                    if neuron_update {
                        *value = new_value;
                    }

                    stack.push(*weight * new_value);
                },
                Forward => {
                    // This is inefficient because it can run the neuron evaluation code multiple
                    // times
                    // TODO: Turn current value of neurons into a struct with a flag representing
                    // whether the neuron has been evaluated this network evaluation. Reset this
                    // flag after every network evaluation.

                    // If the gene is a forward jumper, evaluate the subnetwork starting at the
                    // neuron with id of the jumper, and push the result multiplied by the jumpers
                    // weight onto the stack
                    let weight = self.genome[gene_index].weight;
                    let id = self.genome[gene_index].id;
                    let subnetwork_range = self.get_subnetwork_index(id).unwrap();

                    let result = self.evaluate_slice(subnetwork_range, false);
                    // println!("{:?}", result);
                    stack.push(weight * result[0]);
                },
                Recurrent => {
                    // If the gene is a recurrent jumper, push the previous value of the neuron
                    // with the id of the jumper multiplied by the jumpers weight onto the stack
                    let gene = &self.genome[gene_index];
                    let neuron = &self.genome[self.get_neuron_index(gene.id).unwrap()];

                    if let Neuron(ref current_value, _) = neuron.variant {
                        stack.push(gene.weight * *current_value);
                    }
                },
                Bias => {
                    // If the gene is a bias input, push the bias constant multiplied by the genes
                    // weight onto the stack
                    let gene = &self.genome[gene_index];
                    stack.push(gene.weight * BIAS_GENE_VALUE);
                }
            }

            if gene_index == range.start {
                break;
            }

            gene_index -= 1;
            // println!("{:?}", stack.data);
        }

        stack.data
    }

    // Returns the start and end index of the subnetwork starting at the neuron with the given id,
    // or None if it does not exist
    fn get_subnetwork_index(&self, id: usize) -> Option<Range<usize>> {
        let start = match self.get_neuron_index(id) {
            Some(i) => i,
            None => return None
        };

        let mut end = start;
        let mut sum = 0;

        // Iterate through genes after the start index, modifying the sum each step
        // I could use an iterator here, but it would be messy
        for gene in &self.genome[start..self.size] {
            match gene.variant {
                Neuron(_, ref inputs) => {
                    sum += 1 - *inputs as i32;
                },
                _ => {
                    sum += 1;
                }
            }

            if sum == 1 {
                break;
            }

            end += 1;
        }

        if sum != 1 {
            None
        } else {
            Some(Range {
                start: start,
                end: end
            })
        }
    }

    /// Returns the index of the neuron with the given id, or None if it does not exist.
    pub fn get_neuron_index(&self, id: usize) -> Option<usize> {
        let mut result = None;

        for (i, gene) in self.genome.iter().enumerate() {
            if let Neuron(_, _) = gene.variant {
                if gene.id == id {
                    result = Some(i);
                }
            }
        }

        result
    }
}
<commit_msg>Revert previous commit<commit_after>//! The neural network struct. See the module level documentation for usage.

use std::ops::Range;
use std::io;

use utils::Stack;
use file;
use gene::*;
use gene::GeneExtras::*;

const BIAS_GENE_VALUE: f64 = 1.0;

#[derive(Clone, Debug, PartialEq)]
pub struct Network {
    // size should be the length of the genome minus one, don't forget
    pub size: usize,
    pub genome: Vec<Gene>
}

impl Network {
    /// Evaluates the neural network with the given inputs, returning a vector of outputs. The encoding can
    /// encode recurrent connections and bias inputs, so an internal state is used. It is important to run
    /// the clear_state method before calling evaluate again, unless it is desired to allow data
    /// carry over from the previous evaluation, for example if the network is being used as a real
    /// time controller.
    ///
    /// If too little inputs are given, the empty inputs will have a value of zero. If too many
    /// inputs are given, the extras are discarded.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use cge::Network;
    ///
    /// // Load a neural network
    /// let mut network = Network::load_from_file("neural_network.ann").unwrap();
    ///
    /// // Get the output of the neural network the the specified inputs
    /// let result = network.evaluate(&vec![1.0, 1.0]);
    ///
    /// // Get the output of the neural network with no inputs
    /// let result = network.evaluate(&Vec::new());
    ///
    /// // Get the output of the neural network with too many inputs (extras aren't used)
    /// let result = network.evaluate(&vec![1.0, 1.0, 1.0]);
    ///
    /// // Let's say adder.ann is a file with a neural network with recurrent connections, used for
    /// // adding numbers together.
    /// let mut adder = Network::load_from_file("adder.ann").unwrap();
    ///
    /// // result_one will be 1.0
    /// let result_one = adder.evaluate(&vec![1.0]);
    ///
    /// // result_two will be 3.0
    /// let result_two = adder.evaluate(&vec![2.0]);
    ///
    /// // result_three will be 5.0
    /// let result_three = adder.evaluate(&vec![2.0]);
    ///
    /// // If this behavior is not desired, call the clear_state method between evaluations:
    /// let result_one = adder.evaluate(&vec![1.0]);
    ///
    /// adder.clear_state();
    ///
    /// // The 1.0 from the previous call is gone, so result_two will be 2.0
    /// let result_two = adder.evaluate(&vec![2.0]);
    /// ```
    pub fn evaluate(&mut self, inputs: &Vec<f64>) -> Vec<f64> {
        // Set inputs
        for gene in &mut self.genome {
            if let Input(ref mut current_value) = gene.variant {
                *current_value = match inputs.get(gene.id) {
                    Some(v) => *v,
                    None => 0.0
                }
            }
        }

        let size = self.size;
        self.evaluate_slice(0..size, true)
    }

    /// Clears the internal state of the neural network.
    pub fn clear_state(&mut self) {
        for gene in &mut self.genome {
            match gene.variant {
                Input(ref mut current_value) => {
                    *current_value = 0.0;
                },
                Neuron(ref mut current_value, _) => {
                    *current_value = 0.0;
                }
                _ => {}
            }
        }
    }

    /// Saves the neural network to a file. Returns an empty tuple on success, or an io error.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use cge::Network;
    ///
    /// // Create a neural network
    /// let network = Network {
    ///     size: 0,
    ///     genome: Vec::new()
    /// };
    ///
    /// // Save network to neural_network.ann
    /// network.save_to_file("neural_network.ann");
    /// ```
    pub fn save_to_file(&self, path: &str) -> io::Result<()> {
        file::write_network(self, path)
    }

    /// Loads a neural network from a file. No guarantees are made about the validity of the
    /// genome. Returns the network, or an io error. If the file is in a bad format,
    /// io::ErrorKind::InvalidData is returned.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use cge::Network;
    ///
    /// // Loads a network from the file neural_network.ann
    /// let mut network = Network::load_from_file("neural_network.ann").unwrap();
    /// ```
    pub fn load_from_file(path: &str) -> io::Result<Network> {
        file::read_network(path)
    }

    // Returns the output of sub-linear genome in the given range
    fn evaluate_slice(&mut self, range: Range<usize>, neuron_update: bool) -> Vec<f64> {
        let mut gene_index = range.end;
        // Initialize a stack for evaluating the neural network
        let mut stack = Stack::new();

        // Iterate backwards over the specified slice
        while gene_index >= range.start {
            let variant = self.genome[gene_index].variant.clone();

            // For debugging: uncomment these print statements
            // Perhaps add it as an option to help users
            // println!("{:?}", variant);

            match variant {
                Input(_) => {
                    // If the gene is an input, push its value multiplied by the inputs weight onto
                    // the stack
                    let (weight, _, value) = self.genome[gene_index].ref_input().unwrap();
                    stack.push(weight * value);
                },
                Neuron(_, _) => {
                    // If the gene is a neuron, pop a number (the neurons input count) of inputs
                    // off the stack, and push their sum multiplied by the neurons weight onto the
                    // stack
                    let (weight, _, value, inputs) = self.genome[gene_index].ref_mut_neuron().unwrap();
                    let new_value = stack.pop(*inputs).unwrap().iter().fold(0.0, |acc, i| acc + i);

                    if neuron_update {
                        *value = new_value;
                    }

                    stack.push(*weight * new_value);
                },
                Forward => {
                    // This is inefficient because it can run the neuron evaluation code multiple
                    // times
                    // TODO: Turn current value of neurons into a struct with a flag representing
                    // whether the neuron has been evaluated this network evaluation. Reset this
                    // flag after every network evaluation.

                    // If the gene is a forward jumper, evaluate the subnetwork starting at the
                    // neuron with id of the jumper, and push the result multiplied by the jumpers
                    // weight onto the stack
                    let weight = self.genome[gene_index].weight;
                    let id = self.genome[gene_index].id;
                    let subnetwork_range = self.get_subnetwork_index(id).unwrap();

                    let result = self.evaluate_slice(subnetwork_range, false);
                    // println!("{:?}", result);
                    stack.push(weight * result[0]);
                },
                Recurrent => {
                    // If the gene is a recurrent jumper, push the previous value of the neuron
                    // with the id of the jumper multiplied by the jumpers weight onto the stack
                    let gene = &self.genome[gene_index];
                    let neuron = &self.genome[self.get_neuron_index(gene.id).unwrap()];

                    if let Neuron(ref current_value, _) = neuron.variant {
                        stack.push(gene.weight * *current_value);
                    }
                },
                Bias => {
                    // If the gene is a bias input, push the bias constant multiplied by the genes
                    // weight onto the stack
                    let gene = &self.genome[gene_index];
                    stack.push(gene.weight * BIAS_GENE_VALUE);
                }
            }

            if gene_index == range.start {
                break;
            }

            gene_index -= 1;
            // println!("{:?}", stack.data);
        }

        stack.data
    }

    // Returns the start and end index of the subnetwork starting at the neuron with the given id,
    // or None if it does not exist
    fn get_subnetwork_index(&self, id: usize) -> Option<Range<usize>> {
        let start = match self.get_neuron_index(id) {
            Some(i) => i,
            None => return None
        };

        let mut end = start;
        let mut sum = 0;

        // Iterate through genes after the start index, modifying the sum each step
        // I could use an iterator here, but it would be messy
        for gene in &self.genome[start..self.size] {
            match gene.variant {
                Neuron(_, ref inputs) => {
                    sum += 1 - *inputs as i32;
                },
                _ => {
                    sum += 1;
                }
            }

            if sum == 1 {
                break;
            }

            end += 1;
        }

        if sum != 1 {
            None
        } else {
            Some(Range {
                start: start,
                end: end
            })
        }
    }

    // Returns the index of the neuron with the given id, or None if it does not exist
    fn get_neuron_index(&self, id: usize) -> Option<usize> {
        let mut result = None;

        for (i, gene) in self.genome.iter().enumerate() {
            if let Neuron(_, _) = gene.variant {
                if gene.id == id {
                    result = Some(i);
                }
            }
        }

        result
    }
}
<|endoftext|>


<commit_before>use libc;
#[cfg(not(target_env = "musl"))]
use crate::Result;
#[cfg(not(target_env = "musl"))]
use crate::errno::Errno;
use std::mem;
use crate::sys::signal::SigSet;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct UContext {
    context: libc::ucontext_t,
}

impl UContext {
    #[cfg(not(target_env = "musl"))]
    pub fn get() -> Result<UContext> {
        let mut context = mem::MaybeUninit::<libc::ucontext_t>::uninit();
        let res = unsafe { libc::getcontext(context.as_mut_ptr()) };
        Errno::result(res).map(|_| unsafe {
            UContext { context: context.assume_init()}
        })
    }

    #[cfg(not(target_env = "musl"))]
    pub fn set(&self) -> Result<()> {
        let res = unsafe {
            libc::setcontext(&self.context as *const libc::ucontext_t)
        };
        Errno::result(res).map(drop)
    }

    pub fn sigmask_mut(&mut self) -> &mut SigSet {
        unsafe {
            &mut *(&mut self.context.uc_sigmask as *mut libc::sigset_t as *mut SigSet)
        }
    }

    pub fn sigmask(&self) -> &SigSet {
        unsafe {
            &*(&self.context.uc_sigmask as *const libc::sigset_t as *const SigSet)
        }
    }
}
<commit_msg>Fix an "unused import" warning on musl<commit_after>use libc;
#[cfg(not(target_env = "musl"))]
use crate::Result;
#[cfg(not(target_env = "musl"))]
use crate::errno::Errno;
#[cfg(not(target_env = "musl"))]
use std::mem;
use crate::sys::signal::SigSet;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct UContext {
    context: libc::ucontext_t,
}

impl UContext {
    #[cfg(not(target_env = "musl"))]
    pub fn get() -> Result<UContext> {
        let mut context = mem::MaybeUninit::<libc::ucontext_t>::uninit();
        let res = unsafe { libc::getcontext(context.as_mut_ptr()) };
        Errno::result(res).map(|_| unsafe {
            UContext { context: context.assume_init()}
        })
    }

    #[cfg(not(target_env = "musl"))]
    pub fn set(&self) -> Result<()> {
        let res = unsafe {
            libc::setcontext(&self.context as *const libc::ucontext_t)
        };
        Errno::result(res).map(drop)
    }

    pub fn sigmask_mut(&mut self) -> &mut SigSet {
        unsafe {
            &mut *(&mut self.context.uc_sigmask as *mut libc::sigset_t as *mut SigSet)
        }
    }

    pub fn sigmask(&self) -> &SigSet {
        unsafe {
            &*(&self.context.uc_sigmask as *const libc::sigset_t as *const SigSet)
        }
    }
}
<|endoftext|>


<commit_before>use prelude::*;
use super::{CheckpointFormat};
use rw::{ReadBuffer, WriteBuffer};

use csv::{Writer as CsvWriter};
use densearray::{Reshape, ReshapeMut};

use rand::{Rng, thread_rng};
use rustc_serialize::{Encodable};
use std::cmp::{max, min};
use std::fmt::{Debug};
use std::fs::{File, create_dir_all};
use std::io::{Write};
use std::path::{Path, PathBuf};
use std::thread::{sleep};
use std::time::{Duration, Instant};

//pub mod adagrad;
pub mod adagrad_new;
//pub mod adam;
pub mod adam_new;
//pub mod rmsprop;
//pub mod sgd;
pub mod sgd_new;
//pub mod shared_sgd;
pub mod shared_sgd_new;

#[derive(Clone, Debug)]
pub struct CheckpointConfig {
  pub prefix:   PathBuf,
  pub trace:    bool,
}

pub struct CheckpointState {
  pub cfg:          CheckpointConfig,
  pub config_file:  Option<File>,
  pub train_file:   Option<CsvWriter<File>>,
  pub valid_file:   Option<CsvWriter<File>>,
  start_time:   Instant,
  lap_time:     Instant,
  elapsed_s:    f64,
}

impl CheckpointState {
  pub fn new(cfg: CheckpointConfig) -> CheckpointState {
    Self::with_fields(cfg, "iter,loss,accuracy,elapsed")
  }

  pub fn with_fields(cfg: CheckpointConfig, fields: &str) -> CheckpointState {
    let delay_s = thread_rng().gen_range(0, 2);
    let delay_ns = thread_rng().gen_range(100_000_000, 500_000_000);
    sleep(Duration::new(delay_s, delay_ns));
    create_dir_all(&cfg.prefix).ok();
    loop {
      let mut lo_idx = Some(0);
      let mut hi_idx = None;
      let mut idx = 0;
      while lo_idx != hi_idx {
        match (lo_idx, hi_idx) {
          (Some(lo), None) => {
            idx = lo;
          }
          (Some(lo), Some(hi)) => {
            idx = (lo + hi) / 2;
          }
          _ => unreachable!(),
        }
        let mut config_path = PathBuf::from(&cfg.prefix);
        let mut config_filename = format!("config.{}", idx);
        config_path.push(&config_filename);
        if config_path.exists() {
          match (lo_idx, hi_idx) {
            (Some(lo), None) => {
              lo_idx = Some(lo + max(1, lo));
            }
            (Some(lo), Some(hi)) => {
              lo_idx = Some(min(hi, max(lo + 1, idx)));
            }
            _ => unreachable!(),
          }
        } else {
          match (lo_idx, hi_idx) {
            (Some(_), None) => {
              lo_idx = Some(idx / 2);
              hi_idx = Some(idx);
            }
            (Some(_), Some(_)) => {
              hi_idx = Some(idx);
            }
            _ => unreachable!(),
          }
        }
      }
      idx = hi_idx.unwrap();

      let delay_s = thread_rng().gen_range(0, 2);
      let delay_ns = thread_rng().gen_range(100_000_000, 500_000_000);
      sleep(Duration::new(delay_s, delay_ns));
      let mut cfg_f = None;
      let mut trace_f = None;
      let mut valid_f = None;
      let mut config_path = PathBuf::from(&cfg.prefix);
      let mut config_filename = format!("config.{}", idx);
      config_path.push(&config_filename);
      if config_path.exists() {
        continue;
      }
      match File::create(&config_path) {
        Err(_) => {
          continue;
        }
        Ok(f) => {
          cfg_f = Some(f);
        }
      }
      if cfg.trace {
        let mut train_path = PathBuf::from(&cfg.prefix);
        let mut train_filename = format!("train.log.{}", idx);
        train_path.push(&train_filename);
        assert!(!train_path.exists());
        let mut f = File::create(&train_path).unwrap();
        writeln!(&mut f, "{}", fields).unwrap();
        trace_f = Some(f);

        let mut valid_path = PathBuf::from(&cfg.prefix);
        let mut valid_filename = format!("valid.log.{}", idx);
        valid_path.push(&valid_filename);
        assert!(!valid_path.exists());
        let mut f = File::create(&valid_path).unwrap();
        writeln!(&mut f, "{}", fields).unwrap();
        valid_f = Some(f);
      }
      let init_time = Instant::now();
      return CheckpointState{
        cfg:          cfg,
        config_file:  cfg_f,
        train_file:   trace_f.map(|f| CsvWriter::from_writer(f)),
        valid_file:   valid_f.map(|f| CsvWriter::from_writer(f)),
        start_time:   init_time,
        lap_time:     init_time,
        elapsed_s:    0.0,
      };
    }
  }

  pub fn start_timing(&mut self) {
    self.start_time = Instant::now();
  }

  pub fn stop_timing(&mut self) {
    self.lap_time = Instant::now();
    let duration = self.lap_time - self.start_time;
    self.elapsed_s = duration.as_secs() as f64 + 1.0e-9 * duration.subsec_nanos() as f64;
  }

  pub fn elapsed(&self) -> f64 {
    self.elapsed_s
  }

  pub fn append_config_info<U>(&mut self, info: &U) where U: Debug {
    if let Some(ref mut config_file) = self.config_file {
      writeln!(config_file, "{:?}", info).unwrap();
    }
  }

  pub fn append_class_stats_train(&mut self, stats: &ClassLossStats) {
    let elapsed = self.elapsed_s;
    self.append_train_info(&stats.to_record(elapsed));
  }

  pub fn append_train_info<Rec>(&mut self, rec: &Rec) where Rec: Encodable {
    if let Some(ref mut train_file) = self.train_file {
      train_file.encode(rec).unwrap();
      //train_file.flush().unwrap();
    }
  }

  pub fn append_class_stats_valid(&mut self, stats: &ClassLossStats) {
    let elapsed = self.elapsed_s;
    self.append_valid_info(&stats.to_record(elapsed));
  }

  pub fn append_valid_info<Rec>(&mut self, rec: &Rec) where Rec: Encodable {
    if let Some(ref mut valid_file) = self.valid_file {
      valid_file.encode(rec).unwrap();
      valid_file.flush().unwrap();
    }
  }
}

pub trait TraceRecord {
  fn loss(&self) -> f32;
  fn other(&self) -> f32;
}

#[derive(Clone, Debug)]
pub enum StepSize {
  Constant(f32),
  Custom{init_step: f32, steps: Vec<(usize, f32)>},
  Decay{init_step: f32, step_decay: f32, decay_iters: usize},
  Adaptive{init_step: f32, test_iters: usize, epoch_iters: usize, sched: AdaptiveStepSizeSchedule},
  BacktrackingLineSearch{decay: f32, c: f32},
  //WeakWolfeLineSearch,
}

#[derive(Clone, Copy, Debug)]
pub enum AdaptiveStepSizeSchedule {
  Pow10,
  Decimal,
}

pub fn adaptive_pow10_step_size_factor(t: usize) -> f32 {
  const F1: [f32; 2] = [0.3,    0.1];
  const F2: [f32; 2] = [0.03,   0.01];
  const F3: [f32; 2] = [0.003,  0.001];
  const F4: [f32; 2] = [0.0003, 0.0001];
  if t == 0 {
    1.0
  } else if t > 0 && t <= 2 {
    F1[t-1]
  } else if t > 2 && t <= 4 {
    F2[t-2-1]
  } else if t > 4 && t <= 6 {
    F3[t-4-1]
  } else if t > 6 && t <= 8 {
    F4[t-6-1]
  } else {
    unimplemented!();
  }
}

pub fn adaptive_decimal_step_size_factor(t: usize) -> f32 {
  const F1: [f32; 9] = [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1];
  const F2: [f32; 9] = [0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.02, 0.01];
  const F3: [f32; 9] = [0.009, 0.008, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001];
  if t == 0 {
    1.0
  } else if t > 0 && t <= 9 {
    F1[t-1]
  } else if t > 9 && t <= 18 {
    F2[t-9-1]
  } else if t > 18 && t <= 27 {
    F3[t-18-1]
  } else {
    unimplemented!();
  }
}

#[derive(Clone, Copy, Debug)]
pub enum GradientMomentum {
  HeavyBall(f32),
  Nesterov(f32),
}

#[derive(Clone, Copy, Debug)]
pub enum NesterovParamState {
  Orig,
  PlusMomentum,
}

#[derive(Clone, Copy, Debug)]
pub struct StepStats {
  pub elapsed:  Option<f64>,
}

pub trait OptWorker<T, S> {
  type Rng: Rng;

  //fn init_param(&mut self, rng: &mut Xorshiftplus128Rng);
  fn init_param(&mut self, rng: &mut Self::Rng);
  /*fn load_local_param(&mut self, param_reader: &mut ReadBuffer<T>);
  fn store_local_param(&mut self, param_writer: &mut WriteBuffer<T>);
  fn store_global_param(&mut self, param_writer: &mut WriteBuffer<T>);*/

  fn step(&mut self, samples: &mut Iterator<Item=S>) /* -> StepStats*/;
  fn eval(&mut self, epoch_size: usize, samples: &mut Iterator<Item=S>);
}

pub trait OptCheckpoint<Format> where Format: CheckpointFormat {
  fn save_checkpoint(&mut self, path: &Path) -> Result<(), ()>;
  fn restore_checkpoint(&mut self, path: &Path) -> Result<(), ()>;
}

pub trait OptStats<Stats> {
  fn reset_opt_stats(&mut self);
  fn get_opt_stats(&self) -> &Stats;
}

pub trait OptUpdateStats<Stats> {
  fn update_stats(&mut self, stats: &mut Stats);
}

#[derive(Clone, Default, Debug)]
pub struct ClassOptStats {
  pub iter_count:       usize,
  pub sample_count:     usize,
  pub correct_count:    usize,
  pub avg_loss:         f32,
}

impl ClassOptStats {
  pub fn reset(&mut self) {
    self.iter_count = 0;
    self.sample_count = 0;
    self.correct_count = 0;
    self.avg_loss = 0.0;
  }

  pub fn accuracy(&self) -> f32 {
    self.correct_count as f32 / self.sample_count as f32
  }
}

#[derive(Clone, Default, Debug)]
pub struct RegressOptStats {
  pub avg_loss:         f32,
}
<commit_msg>Flush both training and validation logs.<commit_after>use prelude::*;
use super::{CheckpointFormat};
use rw::{ReadBuffer, WriteBuffer};

use csv::{Writer as CsvWriter};
use densearray::{Reshape, ReshapeMut};

use rand::{Rng, thread_rng};
use rustc_serialize::{Encodable};
use std::cmp::{max, min};
use std::fmt::{Debug};
use std::fs::{File, create_dir_all};
use std::io::{Write};
use std::path::{Path, PathBuf};
use std::thread::{sleep};
use std::time::{Duration, Instant};

//pub mod adagrad;
pub mod adagrad_new;
//pub mod adam;
pub mod adam_new;
//pub mod rmsprop;
//pub mod sgd;
pub mod sgd_new;
//pub mod shared_sgd;
pub mod shared_sgd_new;

#[derive(Clone, Debug)]
pub struct CheckpointConfig {
  pub prefix:   PathBuf,
  pub trace:    bool,
}

pub struct CheckpointState {
  pub cfg:          CheckpointConfig,
  pub config_file:  Option<File>,
  pub train_file:   Option<CsvWriter<File>>,
  pub valid_file:   Option<CsvWriter<File>>,
  start_time:   Instant,
  lap_time:     Instant,
  elapsed_s:    f64,
}

impl CheckpointState {
  pub fn new(cfg: CheckpointConfig) -> CheckpointState {
    Self::with_fields(cfg, "iter,loss,accuracy,elapsed")
  }

  pub fn with_fields(cfg: CheckpointConfig, fields: &str) -> CheckpointState {
    let delay_s = thread_rng().gen_range(0, 2);
    let delay_ns = thread_rng().gen_range(100_000_000, 500_000_000);
    sleep(Duration::new(delay_s, delay_ns));
    create_dir_all(&cfg.prefix).ok();
    loop {
      let mut lo_idx = Some(0);
      let mut hi_idx = None;
      let mut idx = 0;
      while lo_idx != hi_idx {
        match (lo_idx, hi_idx) {
          (Some(lo), None) => {
            idx = lo;
          }
          (Some(lo), Some(hi)) => {
            idx = (lo + hi) / 2;
          }
          _ => unreachable!(),
        }
        let mut config_path = PathBuf::from(&cfg.prefix);
        let mut config_filename = format!("config.{}", idx);
        config_path.push(&config_filename);
        if config_path.exists() {
          match (lo_idx, hi_idx) {
            (Some(lo), None) => {
              lo_idx = Some(lo + max(1, lo));
            }
            (Some(lo), Some(hi)) => {
              lo_idx = Some(min(hi, max(lo + 1, idx)));
            }
            _ => unreachable!(),
          }
        } else {
          match (lo_idx, hi_idx) {
            (Some(_), None) => {
              lo_idx = Some(idx / 2);
              hi_idx = Some(idx);
            }
            (Some(_), Some(_)) => {
              hi_idx = Some(idx);
            }
            _ => unreachable!(),
          }
        }
      }
      idx = hi_idx.unwrap();

      let delay_s = thread_rng().gen_range(0, 2);
      let delay_ns = thread_rng().gen_range(100_000_000, 500_000_000);
      sleep(Duration::new(delay_s, delay_ns));
      let mut cfg_f = None;
      let mut trace_f = None;
      let mut valid_f = None;
      let mut config_path = PathBuf::from(&cfg.prefix);
      let mut config_filename = format!("config.{}", idx);
      config_path.push(&config_filename);
      if config_path.exists() {
        continue;
      }
      match File::create(&config_path) {
        Err(_) => {
          continue;
        }
        Ok(f) => {
          cfg_f = Some(f);
        }
      }
      if cfg.trace {
        let mut train_path = PathBuf::from(&cfg.prefix);
        let mut train_filename = format!("train.log.{}", idx);
        train_path.push(&train_filename);
        assert!(!train_path.exists());
        let mut f = File::create(&train_path).unwrap();
        writeln!(&mut f, "{}", fields).unwrap();
        trace_f = Some(f);

        let mut valid_path = PathBuf::from(&cfg.prefix);
        let mut valid_filename = format!("valid.log.{}", idx);
        valid_path.push(&valid_filename);
        assert!(!valid_path.exists());
        let mut f = File::create(&valid_path).unwrap();
        writeln!(&mut f, "{}", fields).unwrap();
        valid_f = Some(f);
      }
      let init_time = Instant::now();
      return CheckpointState{
        cfg:          cfg,
        config_file:  cfg_f,
        train_file:   trace_f.map(|f| CsvWriter::from_writer(f)),
        valid_file:   valid_f.map(|f| CsvWriter::from_writer(f)),
        start_time:   init_time,
        lap_time:     init_time,
        elapsed_s:    0.0,
      };
    }
  }

  pub fn start_timing(&mut self) {
    self.start_time = Instant::now();
  }

  pub fn stop_timing(&mut self) {
    self.lap_time = Instant::now();
    let duration = self.lap_time - self.start_time;
    self.elapsed_s = duration.as_secs() as f64 + 1.0e-9 * duration.subsec_nanos() as f64;
  }

  pub fn elapsed(&self) -> f64 {
    self.elapsed_s
  }

  pub fn append_config_info<U>(&mut self, info: &U) where U: Debug {
    if let Some(ref mut config_file) = self.config_file {
      writeln!(config_file, "{:?}", info).unwrap();
    }
  }

  pub fn append_class_stats_train(&mut self, stats: &ClassLossStats) {
    let elapsed = self.elapsed_s;
    self.append_train_info(&stats.to_record(elapsed));
  }

  pub fn append_train_info<Rec>(&mut self, rec: &Rec) where Rec: Encodable {
    if let Some(ref mut train_file) = self.train_file {
      train_file.encode(rec).unwrap();
      train_file.flush().unwrap();
    }
  }

  pub fn append_class_stats_valid(&mut self, stats: &ClassLossStats) {
    let elapsed = self.elapsed_s;
    self.append_valid_info(&stats.to_record(elapsed));
  }

  pub fn append_valid_info<Rec>(&mut self, rec: &Rec) where Rec: Encodable {
    if let Some(ref mut valid_file) = self.valid_file {
      valid_file.encode(rec).unwrap();
      valid_file.flush().unwrap();
    }
  }
}

pub trait TraceRecord {
  fn loss(&self) -> f32;
  fn other(&self) -> f32;
}

#[derive(Clone, Debug)]
pub enum StepSize {
  Constant(f32),
  Custom{init_step: f32, steps: Vec<(usize, f32)>},
  Decay{init_step: f32, step_decay: f32, decay_iters: usize},
  Adaptive{init_step: f32, test_iters: usize, epoch_iters: usize, sched: AdaptiveStepSizeSchedule},
  BacktrackingLineSearch{decay: f32, c: f32},
  //WeakWolfeLineSearch,
}

#[derive(Clone, Copy, Debug)]
pub enum AdaptiveStepSizeSchedule {
  Pow10,
  Decimal,
}

pub fn adaptive_pow10_step_size_factor(t: usize) -> f32 {
  const F1: [f32; 2] = [0.3,    0.1];
  const F2: [f32; 2] = [0.03,   0.01];
  const F3: [f32; 2] = [0.003,  0.001];
  const F4: [f32; 2] = [0.0003, 0.0001];
  if t == 0 {
    1.0
  } else if t > 0 && t <= 2 {
    F1[t-1]
  } else if t > 2 && t <= 4 {
    F2[t-2-1]
  } else if t > 4 && t <= 6 {
    F3[t-4-1]
  } else if t > 6 && t <= 8 {
    F4[t-6-1]
  } else {
    unimplemented!();
  }
}

pub fn adaptive_decimal_step_size_factor(t: usize) -> f32 {
  const F1: [f32; 9] = [0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1];
  const F2: [f32; 9] = [0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.02, 0.01];
  const F3: [f32; 9] = [0.009, 0.008, 0.007, 0.006, 0.005, 0.004, 0.003, 0.002, 0.001];
  if t == 0 {
    1.0
  } else if t > 0 && t <= 9 {
    F1[t-1]
  } else if t > 9 && t <= 18 {
    F2[t-9-1]
  } else if t > 18 && t <= 27 {
    F3[t-18-1]
  } else {
    unimplemented!();
  }
}

#[derive(Clone, Copy, Debug)]
pub enum GradientMomentum {
  HeavyBall(f32),
  Nesterov(f32),
}

#[derive(Clone, Copy, Debug)]
pub enum NesterovParamState {
  Orig,
  PlusMomentum,
}

#[derive(Clone, Copy, Debug)]
pub struct StepStats {
  pub elapsed:  Option<f64>,
}

pub trait OptWorker<T, S> {
  type Rng: Rng;

  //fn init_param(&mut self, rng: &mut Xorshiftplus128Rng);
  fn init_param(&mut self, rng: &mut Self::Rng);
  /*fn load_local_param(&mut self, param_reader: &mut ReadBuffer<T>);
  fn store_local_param(&mut self, param_writer: &mut WriteBuffer<T>);
  fn store_global_param(&mut self, param_writer: &mut WriteBuffer<T>);*/

  fn step(&mut self, samples: &mut Iterator<Item=S>) /* -> StepStats*/;
  fn eval(&mut self, epoch_size: usize, samples: &mut Iterator<Item=S>);
}

pub trait OptCheckpoint<Format> where Format: CheckpointFormat {
  fn save_checkpoint(&mut self, path: &Path) -> Result<(), ()>;
  fn restore_checkpoint(&mut self, path: &Path) -> Result<(), ()>;
}

pub trait OptStats<Stats> {
  fn reset_opt_stats(&mut self);
  fn get_opt_stats(&self) -> &Stats;
}

pub trait OptUpdateStats<Stats> {
  fn update_stats(&mut self, stats: &mut Stats);
}

#[derive(Clone, Default, Debug)]
pub struct ClassOptStats {
  pub iter_count:       usize,
  pub sample_count:     usize,
  pub correct_count:    usize,
  pub avg_loss:         f32,
}

impl ClassOptStats {
  pub fn reset(&mut self) {
    self.iter_count = 0;
    self.sample_count = 0;
    self.correct_count = 0;
    self.avg_loss = 0.0;
  }

  pub fn accuracy(&self) -> f32 {
    self.correct_count as f32 / self.sample_count as f32
  }
}

#[derive(Clone, Default, Debug)]
pub struct RegressOptStats {
  pub avg_loss:         f32,
}
<|endoftext|>


<commit_before>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

pub use {
    Cast,
    Continue,
    StaticType,
    ToValue,
};

#[cfg(gtk_3_4)]
pub use auto::traits::ActionableExt;
pub use auto::traits::BinExt;
pub use auto::traits::BoxExt;
pub use auto::traits::ButtonExt;
pub use auto::traits::CellAreaExt;
pub use auto::traits::CellEditableExt;
pub use auto::traits::CellLayoutExt;
pub use auto::traits::CellRendererExt;
pub use auto::traits::CheckButtonExt;
pub use auto::traits::ComboBoxExt;
pub use auto::traits::ContainerExt;
//pub use auto::traits::DialogExt;
pub use auto::traits::EditableExt;
pub use auto::traits::EntryExt;
pub use auto::traits::FileChooserExt;
pub use auto::traits::FontChooserExt;
pub use auto::traits::FrameExt;
pub use auto::traits::MenuItemExt;
pub use auto::traits::MenuShellExt;
pub use auto::traits::MiscExt;
pub use auto::traits::OrientableExt;
#[cfg(gtk_3_12)]
pub use auto::traits::PopoverExt;
pub use auto::traits::RangeExt;
pub use auto::traits::RecentChooserExt;
pub use auto::traits::ScaleButtonExt;
pub use auto::traits::ScrollableExt;
pub use auto::traits::ScrolledWindowExt;
pub use auto::traits::ToggleButtonExt;
pub use auto::traits::ToolButtonExt;
pub use auto::traits::ToolItemExt;
pub use auto::traits::ToolShellExt;
//pub use auto::traits::TreeModelExt;
pub use auto::traits::TreeSortableExt;
pub use auto::traits::WindowExt;
//pub use auto::traits::WidgetExt;

pub use app_chooser::AppChooserExt;
pub use color_chooser::ColorChooserExt;
pub use dialog::DialogExt;
pub use tree_model::TreeModelExt;
pub use widget::WidgetExt;

pub use signal::*;
<commit_msg>Update the prelude<commit_after>// Copyright 2015-2016, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

pub use {
    Cast,
    Continue,
    StaticType,
    ToValue,
};

#[cfg(gtk_3_4)]
pub use auto::traits::ActionableExt;
pub use auto::traits::BinExt;
pub use auto::traits::BoxExt;
pub use auto::traits::ButtonExt;
pub use auto::traits::CellAreaExt;
pub use auto::traits::CellEditableExt;
pub use auto::traits::CellLayoutExt;
pub use auto::traits::CellRendererExt;
pub use auto::traits::CellRendererTextExt;
pub use auto::traits::CheckButtonExt;
pub use auto::traits::ComboBoxExt;
pub use auto::traits::ContainerExt;
//pub use auto::traits::DialogExt;
pub use auto::traits::EditableExt;
pub use auto::traits::EntryExt;
#[cfg(gtk_3_14)]
pub use auto::traits::EventControllerExt;
pub use auto::traits::FileChooserExt;
pub use auto::traits::FontChooserExt;
pub use auto::traits::FrameExt;
#[cfg(gtk_3_14)]
pub use auto::traits::GestureExt;
#[cfg(gtk_3_14)]
pub use auto::traits::GestureDragExt;
#[cfg(gtk_3_14)]
pub use auto::traits::GestureSingleExt;
pub use auto::traits::MenuItemExt;
pub use auto::traits::MenuShellExt;
pub use auto::traits::MiscExt;
pub use auto::traits::OrientableExt;
#[cfg(gtk_3_12)]
pub use auto::traits::PopoverExt;
pub use auto::traits::RangeExt;
pub use auto::traits::RecentChooserExt;
pub use auto::traits::ScaleButtonExt;
pub use auto::traits::ScrollableExt;
pub use auto::traits::ScrolledWindowExt;
pub use auto::traits::ToggleButtonExt;
pub use auto::traits::ToolButtonExt;
pub use auto::traits::ToolItemExt;
pub use auto::traits::ToolShellExt;
//pub use auto::traits::TreeModelExt;
pub use auto::traits::TreeSortableExt;
//pub use auto::traits::WidgetExt;
pub use auto::traits::WindowExt;

pub use app_chooser::AppChooserExt;
pub use color_chooser::ColorChooserExt;
pub use dialog::DialogExt;
pub use tree_model::TreeModelExt;
pub use widget::WidgetExt;

pub use signal::*;
<|endoftext|>