<commit_before>use nalgebra::Point3;
use num::{Float, Unsigned};
use std::ops::Range;

use super::generate::{Conjoint, Indexed};
use super::primitive::{MapInto, Quad};

// TODO: Is there some way to hide these details? Soon, making this trait
//       non-`pub` will cause a compiler error.
pub trait Cube: Iterator + Sized {
    type Point;

    fn point(&self, index: usize) -> Self::Point;

    fn face(&self, index: usize) -> Quad<Self::Point> {
        self.indexed_face(index).map_points_into(|index| self.point(index))
    }

    fn indexed_face(&self, index: usize) -> Quad<usize> {
        match index {
            0 => Quad::new(0, 1, 3, 2),
            1 => Quad::new(6, 7, 5, 4),
            2 => Quad::new(4, 5, 1, 0),
            3 => Quad::new(3, 7, 6, 2),
            4 => Quad::new(0, 2, 6, 4),
            5 => Quad::new(5, 7, 3, 1),
            _ => panic!(),
        }
    }
}

impl<C> Indexed<Quad<usize>> for C
    where C: Cube
{
    fn indexed_polygon(&self, index: usize) -> Quad<usize> {
        self.indexed_face(index)
    }

    fn indexed_polygon_count(&self) -> usize {
        6
    }
}

impl<T, C> Conjoint<T> for C
    where C: Cube<Point = T>
{
    fn conjoint_point(&self, index: usize) -> T {
        self.point(index)
    }

    fn conjoint_point_count(&self) -> usize {
        8
    }
}

pub struct FCube<T>
    where T: Float
{
    faces: Range<usize>,
    low: T,
    high: T,
}

impl<T> FCube<T>
    where T: Float
{
    pub fn with_unit_radius() -> Self {
        FCube {
            faces: 0..6,
            low: -T::one(),
            high: T::one(),
        }
    }

    pub fn with_unit_width() -> Self {
        let half = T::one() / (T::one() + T::one());
        FCube {
            faces: 0..6,
            low: -half,
            high: half,
        }
    }
}

impl<T> Cube for FCube<T>
    where T: Float
{
    type Point = Point3<T>;

    fn point(&self, index: usize) -> Self::Point {
        point(index, self.low, self.high)
    }
}

impl<T> Iterator for FCube<T>
    where T: Float
{
    type Item = Quad<<Self as Cube>::Point>;

    fn next(&mut self) -> Option<Self::Item> {
        self.faces.next().map(|index| self.face(index))
    }
}

pub struct UCube<T>
    where T: Copy + Unsigned
{
    faces: Range<usize>,
    low: T,
    high: T,
}

impl<T> UCube<T>
    where T: Copy + Unsigned
{
    pub fn with_unit_radius() -> Self {
        UCube {
            faces: 0..6,
            low: T::zero(),
            high: T::one() + T::one(),
        }
    }

    pub fn with_unit_width() -> Self {
        UCube {
            faces: 0..6,
            low: T::zero(),
            high: T::one(),
        }
    }
}

impl<T> Cube for UCube<T>
    where T: Copy + Unsigned
{
    type Point = Point3<T>;

    fn point(&self, index: usize) -> Self::Point {
        point(index, self.low, self.high)
    }
}

impl<T> Iterator for UCube<T>
    where T: Copy + Unsigned
{
    type Item = Quad<<Self as Cube>::Point>;

    fn next(&mut self) -> Option<Self::Item> {
        self.faces.next().map(|index| self.face(index))
    }
}

fn point<T>(index: usize, low: T, high: T) -> Point3<T>
    where T: Copy
{
    let x = if index & 0b100 == 0b100 { high } else { low };
    let y = if index & 0b010 == 0b010 { high } else { low };
    let z = if index & 0b001 == 0b001 { high } else { low };
    Point3::new(x, y, z)
}
<commit_msg>Refactor cube constructors.<commit_after>use nalgebra::Point3;
use num::{Float, Unsigned};
use std::ops::Range;

use super::generate::{Conjoint, Indexed};
use super::primitive::{MapInto, Quad};

// TODO: Is there some way to hide these details? Soon, making this trait
//       non-`pub` will cause a compiler error.
pub trait Cube: Iterator + Sized {
    type Point;

    fn point(&self, index: usize) -> Self::Point;

    fn face(&self, index: usize) -> Quad<Self::Point> {
        self.indexed_face(index).map_points_into(|index| self.point(index))
    }

    fn indexed_face(&self, index: usize) -> Quad<usize> {
        match index {
            0 => Quad::new(0, 1, 3, 2),
            1 => Quad::new(6, 7, 5, 4),
            2 => Quad::new(4, 5, 1, 0),
            3 => Quad::new(3, 7, 6, 2),
            4 => Quad::new(0, 2, 6, 4),
            5 => Quad::new(5, 7, 3, 1),
            _ => panic!(),
        }
    }
}

impl<C> Indexed<Quad<usize>> for C
    where C: Cube
{
    fn indexed_polygon(&self, index: usize) -> Quad<usize> {
        self.indexed_face(index)
    }

    fn indexed_polygon_count(&self) -> usize {
        6
    }
}

impl<T, C> Conjoint<T> for C
    where C: Cube<Point = T>
{
    fn conjoint_point(&self, index: usize) -> T {
        self.point(index)
    }

    fn conjoint_point_count(&self) -> usize {
        8
    }
}

pub struct FCube<T>
    where T: Float
{
    faces: Range<usize>,
    low: T,
    high: T,
}

impl<T> FCube<T>
    where T: Float
{
    fn new(low: T, high: T) -> Self {
        FCube {
            faces: 0..6,
            low: low,
            high: high,
        }
    }

    pub fn with_unit_radius() -> Self {
        FCube::new(-T::one(), T::one())
    }

    pub fn with_unit_width() -> Self {
        let half = T::one() / (T::one() + T::one());
        FCube::new(-half, half)
    }
}

impl<T> Cube for FCube<T>
    where T: Float
{
    type Point = Point3<T>;

    fn point(&self, index: usize) -> Self::Point {
        point(index, self.low, self.high)
    }
}

impl<T> Iterator for FCube<T>
    where T: Float
{
    type Item = Quad<<Self as Cube>::Point>;

    fn next(&mut self) -> Option<Self::Item> {
        self.faces.next().map(|index| self.face(index))
    }
}

pub struct UCube<T>
    where T: Copy + Unsigned
{
    faces: Range<usize>,
    low: T,
    high: T,
}

impl<T> UCube<T>
    where T: Copy + Unsigned
{
    fn new(low: T, high: T) -> Self {
        UCube {
            faces: 0..6,
            low: low,
            high: high,
        }
    }

    pub fn with_unit_radius() -> Self {
        UCube::new(T::zero(), T::one() + T::one())
    }

    pub fn with_unit_width() -> Self {
        UCube::new(T::zero(), T::one())
    }
}

impl<T> Cube for UCube<T>
    where T: Copy + Unsigned
{
    type Point = Point3<T>;

    fn point(&self, index: usize) -> Self::Point {
        point(index, self.low, self.high)
    }
}

impl<T> Iterator for UCube<T>
    where T: Copy + Unsigned
{
    type Item = Quad<<Self as Cube>::Point>;

    fn next(&mut self) -> Option<Self::Item> {
        self.faces.next().map(|index| self.face(index))
    }
}

fn point<T>(index: usize, low: T, high: T) -> Point3<T>
    where T: Copy
{
    let x = if index & 0b100 == 0b100 { high } else { low };
    let y = if index & 0b010 == 0b010 { high } else { low };
    let z = if index & 0b001 == 0b001 { high } else { low };
    Point3::new(x, y, z)
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use std::mem;

mod board;

pub use self::board::{Board, Outcome};
use ai::AIHandle;

pub struct Model {
    pub board: Board,
    pub players: ColorMap<PlayerType>,
    pub last_move: Option<Move>,
    pub selected_piece: Option<FieldCoord>,
    pub available_moves: Option<Vec<FieldCoord>>,
    pub exchanging: bool,
    pub ai_handle: Option<AIHandle>,
    undo_stack: Vec<(Board, Option<Move>)>,
    redo_stack: Vec<(Board, Option<Move>)>,
}

impl Model {
    pub fn new(players: ColorMap<PlayerType>) -> Model {
        Model {
            players,
            ..Default::default()
        }
    }
    pub fn can_undo(&self) -> bool {
        !self.undo_stack.is_empty()
    }
    pub fn can_redo(&self) -> bool {
        !self.redo_stack.is_empty()
    }
    pub fn commit_state(&mut self) {
        self.undo_stack.push((self.board, self.last_move));
        self.redo_stack.clear();
    }
    pub fn undo_move(&mut self) {
        if let Some((board, last_move)) = self.undo_stack.pop() {
            self.redo_stack.push((
                mem::replace(&mut self.board, board),
                mem::replace(&mut self.last_move, last_move),
            ));

            self.clear_selection();
            self.exchanging = false;
        }
    }
    pub fn redo_move(&mut self) {
        if let Some((board, last_move)) = self.redo_stack.pop() {
            self.undo_stack.push((
                mem::replace(&mut self.board, board),
                mem::replace(&mut self.last_move, last_move),
            ));

            self.clear_selection();
            self.exchanging = false;
        }
    }
    pub fn clear_selection(&mut self) {
        self.selected_piece = None;
        self.available_moves = None;
    }
    pub fn is_ai_turn(&self) -> bool {
        self.players.get_ref(self.board.turn()) == &PlayerType::Computer
    }
    pub fn is_game_over(&self) -> bool {
        self.board.outcome() != Outcome::InProgress
    }
}

impl Default for Model {
    fn default() -> Self {
        Model {
            board: Board::new(),
            players: ColorMap::new(PlayerType::Human, PlayerType::Human),
            selected_piece: None,
            last_move: None,
            available_moves: None,
            exchanging: false,
            ai_handle: None,
            undo_stack: vec![],
            redo_stack: vec![],
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Color {
    White,
    Black,
}

impl Color {
    pub fn switch(&self) -> Color {
        match *self {
            Color::White => Color::Black,
            Color::Black => Color::White,
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum PlayerType {
    Human,
    Computer,
}

#[derive(Clone, Copy)]
pub enum Move {
    Exchange(FieldCoord),
    Move(FieldCoord, FieldCoord),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

/// A map to associate any two values with the variants of the Color enum. Useful for keeping
/// track of player-specific information, which almost always comes in pairs.
#[derive(Clone, Copy, PartialEq)]
pub struct ColorMap<T> {
    pub white: T,
    pub black: T,
}

impl<T> ColorMap<T> {
    pub fn new(white: T, black: T) -> ColorMap<T> {
        ColorMap { white, black }
    }
    pub fn get_ref(&self, color: Color) -> &T {
        match color {
            Color::White => &self.white,
            Color::Black => &self.black,
        }
    }
    pub fn get_mut(&mut self, color: Color) -> &mut T {
        match color {
            Color::White => &mut self.white,
            Color::Black => &mut self.black,
        }
    }
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!(Self::is_valid_coord(x, y, f));
        FieldCoord { x, y, f }
    }
    pub fn f(&self) -> u32 {
        self.f
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
    fn is_valid_coord(x: i32, y: i32, f: u32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6
    }
    pub fn color(&self) -> Color {
        if self.f % 2 == 0 {
            Color::Black
        } else {
            Color::White
        }
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!(Self::is_valid_coord(x, y));
        HexCoord { x, y }
    }
    pub fn try_new(x: i32, y: i32) -> Option<HexCoord> {
        if Self::is_valid_coord(x, y) {
            Some(HexCoord { x, y })
        } else {
            None
        }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    fn is_valid_coord(x: i32, y: i32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2
    }
}
<commit_msg>Skip is_valid_coord assert when converting coords<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use std::mem;

mod board;

pub use self::board::{Board, Outcome};
use ai::AIHandle;

pub struct Model {
    pub board: Board,
    pub players: ColorMap<PlayerType>,
    pub last_move: Option<Move>,
    pub selected_piece: Option<FieldCoord>,
    pub available_moves: Option<Vec<FieldCoord>>,
    pub exchanging: bool,
    pub ai_handle: Option<AIHandle>,
    undo_stack: Vec<(Board, Option<Move>)>,
    redo_stack: Vec<(Board, Option<Move>)>,
}

impl Model {
    pub fn new(players: ColorMap<PlayerType>) -> Model {
        Model {
            players,
            ..Default::default()
        }
    }
    pub fn can_undo(&self) -> bool {
        !self.undo_stack.is_empty()
    }
    pub fn can_redo(&self) -> bool {
        !self.redo_stack.is_empty()
    }
    pub fn commit_state(&mut self) {
        self.undo_stack.push((self.board, self.last_move));
        self.redo_stack.clear();
    }
    pub fn undo_move(&mut self) {
        if let Some((board, last_move)) = self.undo_stack.pop() {
            self.redo_stack.push((
                mem::replace(&mut self.board, board),
                mem::replace(&mut self.last_move, last_move),
            ));

            self.clear_selection();
            self.exchanging = false;
        }
    }
    pub fn redo_move(&mut self) {
        if let Some((board, last_move)) = self.redo_stack.pop() {
            self.undo_stack.push((
                mem::replace(&mut self.board, board),
                mem::replace(&mut self.last_move, last_move),
            ));

            self.clear_selection();
            self.exchanging = false;
        }
    }
    pub fn clear_selection(&mut self) {
        self.selected_piece = None;
        self.available_moves = None;
    }
    pub fn is_ai_turn(&self) -> bool {
        self.players.get_ref(self.board.turn()) == &PlayerType::Computer
    }
    pub fn is_game_over(&self) -> bool {
        self.board.outcome() != Outcome::InProgress
    }
}

impl Default for Model {
    fn default() -> Self {
        Model {
            board: Board::new(),
            players: ColorMap::new(PlayerType::Human, PlayerType::Human),
            selected_piece: None,
            last_move: None,
            available_moves: None,
            exchanging: false,
            ai_handle: None,
            undo_stack: vec![],
            redo_stack: vec![],
        }
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Color {
    White,
    Black,
}

impl Color {
    pub fn switch(&self) -> Color {
        match *self {
            Color::White => Color::Black,
            Color::Black => Color::White,
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum PlayerType {
    Human,
    Computer,
}

#[derive(Clone, Copy)]
pub enum Move {
    Exchange(FieldCoord),
    Move(FieldCoord, FieldCoord),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

/// A map to associate any two values with the variants of the Color enum. Useful for keeping
/// track of player-specific information, which almost always comes in pairs.
#[derive(Clone, Copy, PartialEq)]
pub struct ColorMap<T> {
    pub white: T,
    pub black: T,
}

impl<T> ColorMap<T> {
    pub fn new(white: T, black: T) -> ColorMap<T> {
        ColorMap { white, black }
    }
    pub fn get_ref(&self, color: Color) -> &T {
        match color {
            Color::White => &self.white,
            Color::Black => &self.black,
        }
    }
    pub fn get_mut(&mut self, color: Color) -> &mut T {
        match color {
            Color::White => &mut self.white,
            Color::Black => &mut self.black,
        }
    }
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!(Self::is_valid_coord(x, y, f));
        FieldCoord { x, y, f }
    }
    pub fn f(&self) -> u32 {
        self.f
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord {
            x: self.x,
            y: self.y,
        }
    }
    fn is_valid_coord(x: i32, y: i32, f: u32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6
    }
    pub fn color(&self) -> Color {
        if self.f % 2 == 0 {
            Color::Black
        } else {
            Color::White
        }
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!(Self::is_valid_coord(x, y));
        HexCoord { x, y }
    }
    pub fn try_new(x: i32, y: i32) -> Option<HexCoord> {
        if Self::is_valid_coord(x, y) {
            Some(HexCoord { x, y })
        } else {
            None
        }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        assert!(f < 6);
        FieldCoord {
            x: self.x,
            y: self.y,
            f,
        }
    }
    fn is_valid_coord(x: i32, y: i32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use std::mem;

mod board;
mod constants;

pub use self::board::{Board, Outcome};
use ai::AIHandle;

pub struct Model {
    pub board: Board,
    pub players: ColorMap<PlayerType>,
    pub last_move: Option<Move>,
    pub selected_piece: Option<FieldCoord>,
    pub available_moves: Option<Vec<FieldCoord>>,
    pub exchanging: bool,
    pub ai_handle: Option<AIHandle>,
    undo_stack: Vec<(Board, Option<Move>)>,
    redo_stack: Vec<(Board, Option<Move>)>,
}

impl Model {
    pub fn new(players: ColorMap<PlayerType>) -> Model {
        Model {
            players,
            ..Default::default()
        }
    }
    pub fn can_undo(&self) -> bool {
        !self.undo_stack.is_empty()
    }
    pub fn can_redo(&self) -> bool {
        !self.redo_stack.is_empty()
    }
    pub fn commit_state(&mut self) {
        self.undo_stack.push((self.board, self.last_move));
        self.redo_stack.clear();
    }
    pub fn undo_move(&mut self) {
        if let Some((board, last_move)) = self.undo_stack.pop() {
            self.redo_stack.push((
                mem::replace(&mut self.board, board),
                mem::replace(&mut self.last_move, last_move),
            ));

            self.clear_selection();
            self.exchanging = false;
        }
    }
    pub fn redo_move(&mut self) {
        if let Some((board, last_move)) = self.redo_stack.pop() {
            self.undo_stack.push((
                mem::replace(&mut self.board, board),
                mem::replace(&mut self.last_move, last_move),
            ));

            self.clear_selection();
            self.exchanging = false;
        }
    }
    pub fn clear_selection(&mut self) {
        self.selected_piece = None;
        self.available_moves = None;
    }
    pub fn is_ai_turn(&self) -> bool {
        self.players.get_ref(self.board.turn()) == &PlayerType::Computer
    }
    pub fn is_game_over(&self) -> bool {
        self.board.outcome() != Outcome::InProgress
    }
}

impl Default for Model {
    fn default() -> Self {
        Model {
            board: Board::new(),
            players: ColorMap::new(PlayerType::Human, PlayerType::Human),
            selected_piece: None,
            last_move: None,
            available_moves: None,
            exchanging: false,
            ai_handle: None,
            undo_stack: vec![],
            redo_stack: vec![],
        }
    }
}

pub type BitBoard = u64;

pub fn pop_bit(bb: &mut BitBoard) -> BitBoard {
    // bb & -bb
    let bit = *bb & (1 + !*bb);
    *bb ^= bit;
    bit
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Color {
    White,
    Black,
}

impl Color {
    pub fn switch(&self) -> Color {
        match *self {
            Color::White => Color::Black,
            Color::Black => Color::White,
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum PlayerType {
    Human,
    Computer,
}

#[derive(Clone, Copy, Debug)]
pub enum Move {
    Exchange(FieldCoord),
    Move(FieldCoord, FieldCoord),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FieldCoord {
    x: i8,
    y: i8,
    f: u8,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct HexCoord {
    x: i8,
    y: i8,
}

/// A map to associate any two values with the variants of the Color enum. Useful for keeping
/// track of player-specific information, which almost always comes in pairs.
#[derive(Clone, Copy, PartialEq)]
pub struct ColorMap<T> {
    pub white: T,
    pub black: T,
}

impl<T> ColorMap<T> {
    pub fn new(white: T, black: T) -> ColorMap<T> {
        ColorMap { white, black }
    }
    pub fn get_ref(&self, color: Color) -> &T {
        match color {
            Color::White => &self.white,
            Color::Black => &self.black,
        }
    }
    pub fn get_mut(&mut self, color: Color) -> &mut T {
        match color {
            Color::White => &mut self.white,
            Color::Black => &mut self.black,
        }
    }
}

impl FieldCoord {
    pub fn new(x: i8, y: i8, f: u8) -> FieldCoord {
        assert!(Self::is_valid_coord(x, y, f));
        FieldCoord { x, y, f }
    }
    pub fn from_index(index: u8, color: Color) -> FieldCoord {
        assert!(index < 57);

        let f = 2 * (index % 3) + match color {
            Color::White => 1,
            Color::Black => 0,
        };

        Self::from_hex_f(index / 3, f)
    }
    pub fn from_hex_f(hex: u8, f: u8) -> FieldCoord {
        assert!(hex < 19);
        assert!(f < 6);

        let hex = hex as i8 + match hex {
            0...2 => 2,
            3...15 => 3,
            16...18 => 4,
            _ => unreachable!(),
        };
        Self::new(hex % 5 - 2, hex / 5 - 2, f as u8)
    }
    pub fn to_index(&self) -> usize {
        self.to_bitboard().trailing_zeros() as usize
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord {
            x: self.x,
            y: self.y,
        }
    }
    pub fn to_bitboard(&self) -> BitBoard {
        let hex = 5 * (self.y + 2) + self.x + 2;
        let hex = hex as u8 - match hex {
            2...4 => 2,
            6...18 => 3,
            20...22 => 4,
            _ => unreachable!(),
        };

        1 << (hex * 3 + self.f / 2)
    }
    pub fn f(&self) -> u8 {
        self.f
    }
    pub fn color(&self) -> Color {
        if self.f % 2 == 0 {
            Color::Black
        } else {
            Color::White
        }
    }
    fn is_valid_coord(x: i8, y: i8, f: u8) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6
    }
}

impl HexCoord {
    pub fn new(x: i8, y: i8) -> HexCoord {
        assert!(Self::is_valid_coord(x, y));
        HexCoord { x, y }
    }
    pub fn try_new(x: i8, y: i8) -> Option<HexCoord> {
        if Self::is_valid_coord(x, y) {
            Some(HexCoord { x, y })
        } else {
            None
        }
    }
    pub fn new_unchecked(x: i8, y: i8) -> HexCoord {
        HexCoord { x, y }
    }
    pub fn x(&self) -> i8 {
        self.x
    }
    pub fn y(&self) -> i8 {
        self.y
    }
    pub fn to_field(&self, f: u8) -> FieldCoord {
        assert!(f < 6);
        FieldCoord {
            x: self.x,
            y: self.y,
            f,
        }
    }
    pub fn to_index(&self) -> usize {
        let hex = 5 * (self.y + 2) + self.x + 2;
        hex as usize - match hex {
            2...4 => 2,
            6...18 => 3,
            20...22 => 4,
            _ => unreachable!(),
        }
    }
    fn is_valid_coord(x: i8, y: i8) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2
    }
}

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

    #[test]
    fn index_reflextivity() {
        for index in 0..57 {
            let white = FieldCoord::from_index(index as u8, Color::White);
            assert_eq!(index, white.to_index());

            let black = FieldCoord::from_index(index as u8, Color::Black);
            assert_eq!(index, black.to_index());
        }
    }
}
<commit_msg>Remove HexCoord::new<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use std::mem;

mod board;
mod constants;

pub use self::board::{Board, Outcome};
use ai::AIHandle;

pub struct Model {
    pub board: Board,
    pub players: ColorMap<PlayerType>,
    pub last_move: Option<Move>,
    pub selected_piece: Option<FieldCoord>,
    pub available_moves: Option<Vec<FieldCoord>>,
    pub exchanging: bool,
    pub ai_handle: Option<AIHandle>,
    undo_stack: Vec<(Board, Option<Move>)>,
    redo_stack: Vec<(Board, Option<Move>)>,
}

impl Model {
    pub fn new(players: ColorMap<PlayerType>) -> Model {
        Model {
            players,
            ..Default::default()
        }
    }
    pub fn can_undo(&self) -> bool {
        !self.undo_stack.is_empty()
    }
    pub fn can_redo(&self) -> bool {
        !self.redo_stack.is_empty()
    }
    pub fn commit_state(&mut self) {
        self.undo_stack.push((self.board, self.last_move));
        self.redo_stack.clear();
    }
    pub fn undo_move(&mut self) {
        if let Some((board, last_move)) = self.undo_stack.pop() {
            self.redo_stack.push((
                mem::replace(&mut self.board, board),
                mem::replace(&mut self.last_move, last_move),
            ));

            self.clear_selection();
            self.exchanging = false;
        }
    }
    pub fn redo_move(&mut self) {
        if let Some((board, last_move)) = self.redo_stack.pop() {
            self.undo_stack.push((
                mem::replace(&mut self.board, board),
                mem::replace(&mut self.last_move, last_move),
            ));

            self.clear_selection();
            self.exchanging = false;
        }
    }
    pub fn clear_selection(&mut self) {
        self.selected_piece = None;
        self.available_moves = None;
    }
    pub fn is_ai_turn(&self) -> bool {
        self.players.get_ref(self.board.turn()) == &PlayerType::Computer
    }
    pub fn is_game_over(&self) -> bool {
        self.board.outcome() != Outcome::InProgress
    }
}

impl Default for Model {
    fn default() -> Self {
        Model {
            board: Board::new(),
            players: ColorMap::new(PlayerType::Human, PlayerType::Human),
            selected_piece: None,
            last_move: None,
            available_moves: None,
            exchanging: false,
            ai_handle: None,
            undo_stack: vec![],
            redo_stack: vec![],
        }
    }
}

pub type BitBoard = u64;

pub fn pop_bit(bb: &mut BitBoard) -> BitBoard {
    // bb & -bb
    let bit = *bb & (1 + !*bb);
    *bb ^= bit;
    bit
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Color {
    White,
    Black,
}

impl Color {
    pub fn switch(&self) -> Color {
        match *self {
            Color::White => Color::Black,
            Color::Black => Color::White,
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum PlayerType {
    Human,
    Computer,
}

#[derive(Clone, Copy, Debug)]
pub enum Move {
    Exchange(FieldCoord),
    Move(FieldCoord, FieldCoord),
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FieldCoord {
    x: i8,
    y: i8,
    f: u8,
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct HexCoord {
    x: i8,
    y: i8,
}

/// A map to associate any two values with the variants of the Color enum. Useful for keeping
/// track of player-specific information, which almost always comes in pairs.
#[derive(Clone, Copy, PartialEq)]
pub struct ColorMap<T> {
    pub white: T,
    pub black: T,
}

impl<T> ColorMap<T> {
    pub fn new(white: T, black: T) -> ColorMap<T> {
        ColorMap { white, black }
    }
    pub fn get_ref(&self, color: Color) -> &T {
        match color {
            Color::White => &self.white,
            Color::Black => &self.black,
        }
    }
    pub fn get_mut(&mut self, color: Color) -> &mut T {
        match color {
            Color::White => &mut self.white,
            Color::Black => &mut self.black,
        }
    }
}

impl FieldCoord {
    pub fn new(x: i8, y: i8, f: u8) -> FieldCoord {
        assert!(Self::is_valid_coord(x, y, f));
        FieldCoord { x, y, f }
    }
    pub fn from_index(index: u8, color: Color) -> FieldCoord {
        assert!(index < 57);

        let f = 2 * (index % 3) + match color {
            Color::White => 1,
            Color::Black => 0,
        };

        Self::from_hex_f(index / 3, f)
    }
    pub fn from_hex_f(hex: u8, f: u8) -> FieldCoord {
        assert!(hex < 19);
        assert!(f < 6);

        let hex = hex as i8 + match hex {
            0...2 => 2,
            3...15 => 3,
            16...18 => 4,
            _ => unreachable!(),
        };
        Self::new(hex % 5 - 2, hex / 5 - 2, f as u8)
    }
    pub fn to_index(&self) -> usize {
        self.to_bitboard().trailing_zeros() as usize
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord {
            x: self.x,
            y: self.y,
        }
    }
    pub fn to_bitboard(&self) -> BitBoard {
        let hex = 5 * (self.y + 2) + self.x + 2;
        let hex = hex as u8 - match hex {
            2...4 => 2,
            6...18 => 3,
            20...22 => 4,
            _ => unreachable!(),
        };

        1 << (hex * 3 + self.f / 2)
    }
    pub fn f(&self) -> u8 {
        self.f
    }
    pub fn color(&self) -> Color {
        if self.f % 2 == 0 {
            Color::Black
        } else {
            Color::White
        }
    }
    fn is_valid_coord(x: i8, y: i8, f: u8) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6
    }
}

impl HexCoord {
    pub fn try_new(x: i8, y: i8) -> Option<HexCoord> {
        if Self::is_valid_coord(x, y) {
            Some(HexCoord { x, y })
        } else {
            None
        }
    }
    pub fn new_unchecked(x: i8, y: i8) -> HexCoord {
        HexCoord { x, y }
    }
    pub fn x(&self) -> i8 {
        self.x
    }
    pub fn y(&self) -> i8 {
        self.y
    }
    pub fn to_field(&self, f: u8) -> FieldCoord {
        assert!(f < 6);
        FieldCoord {
            x: self.x,
            y: self.y,
            f,
        }
    }
    pub fn to_index(&self) -> usize {
        let hex = 5 * (self.y + 2) + self.x + 2;
        hex as usize - match hex {
            2...4 => 2,
            6...18 => 3,
            20...22 => 4,
            _ => unreachable!(),
        }
    }
    fn is_valid_coord(x: i8, y: i8) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2
    }
}

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

    #[test]
    fn index_reflextivity() {
        for index in 0..57 {
            let white = FieldCoord::from_index(index as u8, Color::White);
            assert_eq!(index, white.to_index());

            let black = FieldCoord::from_index(index as u8, Color::Black);
            assert_eq!(index, black.to_index());
        }
    }
}
<|endoftext|>


<commit_before>extern crate polydraw;

use polydraw::{Application, Renderer, Frame};
use polydraw::raster::{Scene, Rasterizer};

struct ClipRenderer {
   rasterizer: Rasterizer,
   div_per_pixel: i64,
}

impl ClipRenderer {
   fn new() -> Self {
      ClipRenderer {
         rasterizer: Rasterizer::new(),
         div_per_pixel: 1000,
      }
   }

   fn create_scene(&self) -> Scene {
      let points = vec![];

      let segments = vec![];

      let circles = vec![];

      let edges = vec![];

      let polys = vec![];

      let colors = vec![];

      Scene {
         points: points,
         segments: segments,
         circles: circles,
         edges: edges,
         polys: polys,
         colors: colors,
      }
   }
}

impl Renderer for ClipRenderer {
   fn render(&mut self, frame: &mut Frame) {
      frame.clear();

      let scene = self.create_scene();

      self.rasterizer.render(&scene, frame, self.div_per_pixel);
   }
}

fn main() {
   let mut renderer = ClipRenderer::new();

   Application::new()
      .renderer(&mut renderer)
      .title("Clip")
      .run();
}
<commit_msg>Two polys clipping scene<commit_after>extern crate polydraw;

use polydraw::geom::point::Point;
use polydraw::{Application, Renderer, Frame};
use polydraw::raster::{Scene, Rasterizer, EdgeType, Poly};

#[derive(Debug, Clone, Copy)]
pub struct Edge {
   pub edge_type: EdgeType,
   pub p1: Point,
   pub p2: Point,
}

impl Edge {
   #[inline]
   pub fn new(edge_type: EdgeType, p1: Point, p2: Point) -> Self {
      Edge {
         edge_type: edge_type,
         p1: p1,
         p2: p2,
      }
   }

   #[inline]
   pub fn vert_top(p1: Point, p2: Point) -> Edge {
      Edge::new(EdgeType::LVT, p1, p2)
   }

   #[inline]
   pub fn vert_bottom(p1: Point, p2: Point) -> Edge {
      Edge::new(EdgeType::LVB, p1, p2)
   }

   #[inline]
   pub fn hori_right(p1: Point, p2: Point) -> Edge {
      Edge::new(EdgeType::LHR, p1, p2)
   }

   #[inline]
   pub fn hori_left(p1: Point, p2: Point) -> Edge {
      Edge::new(EdgeType::LHL, p1, p2)
   }

   #[inline]
   pub fn top_right(p1: Point, p2: Point) -> Edge {
      Edge::new(EdgeType::LTR, p1, p2)
   }

   #[inline]
   pub fn top_left(p1: Point, p2: Point) -> Edge {
      Edge::new(EdgeType::LTL, p1, p2)
   }

   #[inline]
   pub fn bottom_right(p1: Point, p2: Point) -> Edge {
      Edge::new(EdgeType::LBR, p1, p2)
   }

   #[inline]
   pub fn bottom_left(p1: Point, p2: Point) -> Edge {
      Edge::new(EdgeType::LBL, p1, p2)
   }
}

struct ClipRenderer {
   rasterizer: Rasterizer,
   div_per_pixel: i64,

   edges: Vec<Edge>,
   polys: Vec<Poly>,
}

impl ClipRenderer {
   fn new() -> Self {
      let edges = vec![
         Edge::top_left(Point::new(5, 1), Point::new(1, 6)),       // 0
         Edge::top_right(Point::new(1, 6), Point::new(8, 9)),      // 1
         Edge::bottom_right(Point::new(8, 9), Point::new(9, 6)),   // 2
         Edge::bottom_left(Point::new(9, 6), Point::new(5, 1)),    // 3
         Edge::top_right(Point::new(1, 1), Point::new(3, 8)),      // 4
         Edge::bottom_right(Point::new(3, 8), Point::new(10, 4)),  // 5
         Edge::bottom_left(Point::new(10, 4), Point::new(1, 1)),   // 6
      ];

      let polys = vec![
         Poly::new(0, 4, 0),    // 0
         Poly::new(4, 7, 1),    // 1
      ];

      ClipRenderer {
         rasterizer: Rasterizer::new(),
         div_per_pixel: 1000,

         edges: edges,
         polys: polys,
      }
   }

   fn create_scene(&self) -> Scene {
      let points = vec![];

      let segments = vec![];

      let circles = vec![];

      let edges = vec![];

      let polys = vec![];

      let colors = vec![];

      Scene {
         points: points,
         segments: segments,
         circles: circles,
         edges: edges,
         polys: polys,
         colors: colors,
      }
   }
}

impl Renderer for ClipRenderer {
   fn render(&mut self, frame: &mut Frame) {
      frame.clear();

      let scene = self.create_scene();

      self.rasterizer.render(&scene, frame, self.div_per_pixel);
   }
}

fn main() {
   let mut renderer = ClipRenderer::new();

   Application::new()
      .renderer(&mut renderer)
      .title("Clip")
      .run();
}
<|endoftext|>


<commit_before>extern crate vikos;
use vikos::{model, cost, teacher, learn_history, Model};

fn main(){

    //mean is 9, but of course we do not know that yet
    let history = [
    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
    (16.0, 29.0)
    ];
    // The mean is just a simple number ...
    let mut model = model::Constant::new(0.0);
    // ... which minimizes the square error
    let cost = cost::LeastSquares{};
    // Use stochasic gradient descent with an annealed learning rate
    let teacher = teacher::GradientDescentAl{ l0 : 0.3, t : 4.0 };
    // Train 100 (admittedly repetitive) events
    learn_history(&teacher, &cost, &mut model, history.iter().cycle().take(100).cloned());
    // We need an input vector for predictions, the 42 will not influence the mean
    println!("{}", model.predict(&42.0));
    // Since we know the model's type is `Constant`, we could just access the members
    println!("{}", model.c);
}<commit_msg>made mean.rs more concise<commit_after>extern crate vikos;
use vikos::{model, cost, teacher, learn_history};

fn main(){

    //mean is 9, but of course we do not know that yet
    let history = [1.0, 3.0, 4.0, 7.0, 8.0, 11.0, 29.0];
    // The mean is just a simple number ...
    let mut model = model::Constant::new(0.0);
    // ... which minimizes the square error
    let cost = cost::LeastSquares{};
    // Use stochasic gradient descent with an annealed learning rate
    let teacher = teacher::GradientDescentAl{ l0 : 0.3, t : 4.0 };
    // Train 100 (admitettly repetitive) events
    // We use the `map` iterator adaptor to extend an empty feature vector to each data point
    learn_history(&teacher, &cost, &mut model, history.iter().cycle().take(100).map(|&y|((),y)));
    // Since we know the model's type is `Constant`, we could just access the members
    println!("{}", model.c);
}<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// 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::os::unix::io::AsRawFd;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::time::Duration;

use crate::gpio::{
    interrupt::AsyncInterrupt,
    GpioState, Level, Mode,
    PullUpDown::{self, *},
    Result, Trigger,
};

// Maximum GPIO pins on the BCM2835. The actual number of pins
// exposed through the Pi's GPIO header depends on the model.
pub const MAX: usize = 54;

/// Unconfigured GPIO pin.
#[derive(Debug)]
pub struct Pin {
    pub(crate) pin: u8,
    gpio_state: Arc<GpioState>,
}

impl Pin {
    #[inline]
    pub(crate) fn new(pin: u8, gpio_state: Arc<GpioState>) -> Pin {
        Pin { pin, gpio_state }
    }

    /// Consumes the `Pin`, returns an [`InputPin`], sets its mode to [`Mode::Input`],
    /// and disables the pin's built-in pull-up/pull-down resistors.
    ///
    /// [`InputPin`]: struct.InputPin.html
    /// [`Mode::Input`]: enum.Mode.html#variant.Input
    #[inline]
    pub fn into_input(self) -> InputPin {
        InputPin::new(self, Off)
    }

    /// Consumes the `Pin`, returns an [`InputPin`], sets its mode to [`Mode::Input`],
    /// and enables the pin's built-in pull-down resistor.
    ///
    /// The pull-down resistor is disabled when `InputPin` goes out of scope if [`reset_on_drop`]
    /// is set to `true` (default).
    ///
    /// [`InputPin`]: struct.InputPin.html
    /// [`Mode::Input`]: enum.Mode.html#variant.Input
    /// [`reset_on_drop`]: struct.InputPin.html#method.set_reset_on_drop
    #[inline]
    pub fn into_input_pulldown(self) -> InputPin {
        InputPin::new(self, PullDown)
    }

    /// Consumes the `Pin`, returns an [`InputPin`], sets its mode to [`Mode::Input`],
    /// and enables the pin's built-in pull-up resistor.
    ///
    /// The pull-up resistor is disabled when `InputPin` goes out of scope if [`reset_on_drop`]
    /// is set to `true` (default).
    ///
    /// [`InputPin`]: struct.InputPin.html
    /// [`Mode::Input`]: enum.Mode.html#variant.Input
    /// [`reset_on_drop`]: struct.InputPin.html#method.set_reset_on_drop
    #[inline]
    pub fn into_input_pullup(self) -> InputPin {
        InputPin::new(self, PullUp)
    }

    /// Consumes the pin, returns an [`OutputPin`] and sets its mode to [`Mode::Output`].
    ///
    /// [`OutputPin`]: struct.OutputPin.html
    /// [`Mode::Output`]: enum.Mode.html#variant.Output
    #[inline]
    pub fn into_output(self) -> OutputPin {
        OutputPin::new(self)
    }

    /// Consumes the pin, returns an [`AltPin`] and sets its mode to the given mode.
    ///
    /// [`AltPin`]: struct.AltPin.html
    /// [`Mode`]: enum.Mode.html
    #[inline]
    pub fn into_alt(self, mode: Mode) -> AltPin {
        AltPin::new(self, mode)
    }

    /// Returns the GPIO pin number.
    ///
    /// Pins are addressed by their BCM numbers, rather than their physical location.
    #[inline]
    pub fn pin(&self) -> u8 {
        self.pin
    }

    #[inline]
    pub(crate) fn set_mode(&mut self, mode: Mode) {
        self.gpio_state.gpio_mem.set_mode(self.pin, mode);
    }

    /// Returns the current GPIO pin mode.
    #[inline]
    pub fn mode(&self) -> Mode {
        self.gpio_state.gpio_mem.mode(self.pin)
    }

    /// Configures the built-in GPIO pull-up/pull-down resistors.
    #[inline]
    pub(crate) fn set_pullupdown(&self, pud: PullUpDown) {
        self.gpio_state.gpio_mem.set_pullupdown(self.pin, pud);
    }

    /// Reads the pin's current logic level.
    #[inline]
    pub fn read(&self) -> Level {
        self.gpio_state.gpio_mem.level(self.pin)
    }

    #[inline]
    pub(crate) fn set_low(&mut self) {
        self.gpio_state.gpio_mem.set_low(self.pin);
    }

    #[inline]
    pub(crate) fn set_high(&mut self) {
        self.gpio_state.gpio_mem.set_high(self.pin);
    }

    #[inline]
    pub(crate) fn write(&mut self, level: Level) {
        match level {
            Level::Low => self.set_low(),
            Level::High => self.set_high(),
        };
    }
}

impl Drop for Pin {
    fn drop(&mut self) {
        // Release taken pin
        self.gpio_state.pins_taken[self.pin as usize].store(false, Ordering::SeqCst);
    }
}

macro_rules! impl_pin {
    () => {
        /// Returns the GPIO pin number.
        ///
        /// Pins are addressed by their BCM numbers, rather than their physical location.
        #[inline]
        pub fn pin(&self) -> u8 {
            self.pin.pin
        }
    }
}

macro_rules! impl_input {
    () => {
        /// Reads the pin's current logic level.
        #[inline]
        pub fn read(&self) -> Level {
            self.pin.read()
        }

        /// Returns `true` if the pin's logic level is [`Level::Low`].
        ///
        /// [`Level::Low`]: enum.Level.html
        #[inline]
        pub fn is_low(&self) -> bool {
            self.pin.read() == Level::Low
        }

        /// Returns `true` if the pin's logic level is [`Level::High`].
        ///
        /// [`Level::High`]: enum.Level.html
        #[inline]
        pub fn is_high(&self) -> bool {
            self.pin.read() == Level::High
        }
    }
}

macro_rules! impl_output {
    () => {
        /// Sets pin's logic level to [`Level::Low`].
        ///
        /// [`Level::Low`]: enum.Level.html
        #[inline]
        pub fn set_low(&mut self) {
            self.pin.set_low()
        }

        /// Sets pin's logic level to [`Level::High`].
        ///
        /// [`Level::High`]: enum.Level.html
        #[inline]
        pub fn set_high(&mut self) {
            self.pin.set_high()
        }

        /// Sets pin's logic level.
        #[inline]
        pub fn write(&mut self, level: Level) {
            self.pin.write(level)
        }
    }
}

macro_rules! impl_reset_on_drop {
    () => {
        /// Returns the value of `reset_on_drop`.
        pub fn reset_on_drop(&self) -> bool {
            self.reset_on_drop
        }

        /// When enabled, resets the pin's mode and built-in pull-up/pull-down resistors
        /// to their original state when it goes out of scope.
        /// By default, this is set to `true`.
        ///
        /// # Note
        ///
        /// Drop methods aren't called when a program is abnormally terminated, for
        /// instance when a user presses <kbd>Ctrl + C</kbd>, and the `SIGINT` signal
        /// isn't caught. You catch those using crates such as [`simple_signal`].
        ///
        /// [`simple_signal`]: https://crates.io/crates/simple-signal
        pub fn set_reset_on_drop(&mut self, reset_on_drop: bool) {
            self.reset_on_drop = reset_on_drop;
        }
    };
}

macro_rules! impl_drop {
    ($struct:ident) => {
        impl Drop for $struct {
            /// Resets the pin's mode and built-in pull-up/pull-down resistors if
            /// `reset_on_drop` is set to `true` (default).
            fn drop(&mut self) {
                if !self.reset_on_drop {
                    return;
                }

                if let Some(prev_mode) = self.prev_mode {
                    self.pin.set_mode(prev_mode);
                }

                if self.pud_mode != Off {
                    self.pin.set_pullupdown(Off);
                }
            }
        }
    };
}

/// GPIO pin configured as input.
#[derive(Debug)]
pub struct InputPin {
    pub(crate) pin: Pin,
    prev_mode: Option<Mode>,
    async_interrupt: Option<AsyncInterrupt>,
    reset_on_drop: bool,
    pud_mode: PullUpDown,
}

impl InputPin {
    pub(crate) fn new(mut pin: Pin, pud_mode: PullUpDown) -> InputPin {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Input {
            None
        } else {
            pin.set_mode(Mode::Input);
            Some(prev_mode)
        };

        pin.set_pullupdown(pud_mode);

        InputPin {
            pin,
            prev_mode,
            async_interrupt: None,
            reset_on_drop: true,
            pud_mode,
        }
    }

    impl_pin!();
    impl_input!();

    /// Configures a synchronous interrupt trigger.
    ///
    /// After configuring a synchronous interrupt trigger, use [`poll_interrupt`] or
    /// [`Gpio::poll_interrupts`] to block while waiting for a trigger event.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`poll_interrupt`]: #method.poll_interrupt
    /// [`Gpio::poll_interrupts`]: struct.Gpio#method.poll_interrupts
    pub fn set_interrupt(&mut self, trigger: Trigger) -> Result<()> {
        self.clear_async_interrupt()?;

        // Each pin can only be configured for a single trigger type
        (*self.pin.gpio_state.sync_interrupts.lock().unwrap()).set_interrupt(self.pin(), trigger)
    }

    /// Removes a previously configured synchronous interrupt trigger.
    pub fn clear_interrupt(&mut self) -> Result<()> {
        (*self.pin.gpio_state.sync_interrupts.lock().unwrap()).clear_interrupt(self.pin())
    }

    /// Blocks until an interrupt is triggered on the pin, or a timeout occurs.
    ///
    /// This only works after the pin has been configured for synchronous interrupts using
    /// [`set_interrupt`]. Asynchronous interrupt triggers are automatically polled on a separate thread.
    ///
    /// Calling `poll_interrupt` blocks any other calls to `poll_interrupt` (including on other `InputPin`s) or
    /// [`Gpio::poll_interrupts`] until it returns. If you need to poll multiple pins simultaneously, use
    /// [`Gpio::poll_interrupts`] to block while waiting for any of the interrupts to trigger, or switch to
    /// using asynchronous interrupts with [`set_async_interrupt`].
    ///
    /// If `reset` is set to `false`, returns immediately if an interrupt trigger event was cached in a
    /// previous call to `poll_interrupt`.
    /// If `reset` is set to `true`, clears any cached interrupt trigger events before polling.
    ///
    /// The `timeout` duration indicates how long the call will block while waiting
    /// for interrupt trigger events, after which an `Ok(None))` is returned.
    /// `timeout` can be set to `None` to wait indefinitely.
    ///
    /// [`set_interrupt`]: #method.set_interrupt
    /// [`Gpio::poll_interrupts`]: struct.Gpio#method.poll_interrupts
    /// [`set_async_interrupt`]: #method.set_async_interrupt
    pub fn poll_interrupt(
        &mut self,
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<Option<Level>> {
        let opt =
            (*self.pin.gpio_state.sync_interrupts.lock().unwrap()).poll(&[self], reset, timeout)?;

        if let Some(trigger) = opt {
            Ok(Some(trigger.1))
        } else {
            Ok(None)
        }
    }

    /// Configures an asynchronous interrupt trigger, which will execute the callback on a
    /// separate thread when the interrupt is triggered.
    ///
    /// The callback closure or function pointer is called with a single [`Level`] argument.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`Level`]: enum.Level.html
    pub fn set_async_interrupt<C>(&mut self, trigger: Trigger, callback: C) -> Result<()>
    where
        C: FnMut(Level) + Send + 'static,
    {
        self.clear_interrupt()?;
        self.clear_async_interrupt()?;

        self.async_interrupt = Some(AsyncInterrupt::new(
            self.pin.gpio_state.cdev.as_raw_fd(),
            self.pin(),
            trigger,
            callback,
        )?);

        Ok(())
    }

    /// Removes a previously configured asynchronous interrupt trigger.
    pub fn clear_async_interrupt(&mut self) -> Result<()> {
        if let Some(mut interrupt) = self.async_interrupt.take() {
            interrupt.stop()?;
        }

        Ok(())
    }

    impl_reset_on_drop!();
}

impl_drop!(InputPin);

/// GPIO pin configured as output.
#[derive(Debug)]
pub struct OutputPin {
    pin: Pin,
    prev_mode: Option<Mode>,
    reset_on_drop: bool,
    pud_mode: PullUpDown,
}

impl OutputPin {
    pub(crate) fn new(mut pin: Pin) -> OutputPin {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Output {
            None
        } else {
            pin.set_mode(Mode::Output);
            Some(prev_mode)
        };

        OutputPin {
            pin,
            prev_mode,
            reset_on_drop: true,
            pud_mode: Off,
        }
    }

    impl_pin!();
    impl_input!();
    impl_output!();
    impl_reset_on_drop!();
}

impl_drop!(OutputPin);

/// GPIO pin configured with an alternate function.
#[derive(Debug)]
pub struct AltPin {
    pin: Pin,
    mode: Mode,
    prev_mode: Option<Mode>,
    reset_on_drop: bool,
    pud_mode: PullUpDown,
}

impl AltPin {
    pub(crate) fn new(mut pin: Pin, mode: Mode) -> AltPin {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == mode {
            None
        } else {
            pin.set_mode(mode);
            Some(prev_mode)
        };

        AltPin {
            pin,
            mode,
            prev_mode,
            reset_on_drop: true,
            pud_mode: Off,
        }
    }

    impl_pin!();
    impl_input!();
    impl_output!();
    impl_reset_on_drop!();
}

impl_drop!(AltPin);
<commit_msg>Update documentation<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// 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::os::unix::io::AsRawFd;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::time::Duration;

use crate::gpio::{
    interrupt::AsyncInterrupt,
    GpioState, Level, Mode,
    PullUpDown::{self, *},
    Result, Trigger,
};

// Maximum GPIO pins on the BCM2835. The actual number of pins
// exposed through the Pi's GPIO header depends on the model.
pub const MAX: usize = 54;

/// Unconfigured GPIO pin.
#[derive(Debug)]
pub struct Pin {
    pub(crate) pin: u8,
    gpio_state: Arc<GpioState>,
}

impl Pin {
    #[inline]
    pub(crate) fn new(pin: u8, gpio_state: Arc<GpioState>) -> Pin {
        Pin { pin, gpio_state }
    }

    /// Consumes the `Pin`, returns an [`InputPin`], sets its mode to [`Mode::Input`],
    /// and disables the pin's built-in pull-up/pull-down resistors.
    ///
    /// [`InputPin`]: struct.InputPin.html
    /// [`Mode::Input`]: enum.Mode.html#variant.Input
    #[inline]
    pub fn into_input(self) -> InputPin {
        InputPin::new(self, Off)
    }

    /// Consumes the `Pin`, returns an [`InputPin`], sets its mode to [`Mode::Input`],
    /// and enables the pin's built-in pull-down resistor.
    ///
    /// The pull-down resistor is disabled when `InputPin` goes out of scope if [`reset_on_drop`]
    /// is set to `true` (default).
    ///
    /// [`InputPin`]: struct.InputPin.html
    /// [`Mode::Input`]: enum.Mode.html#variant.Input
    /// [`reset_on_drop`]: struct.InputPin.html#method.set_reset_on_drop
    #[inline]
    pub fn into_input_pulldown(self) -> InputPin {
        InputPin::new(self, PullDown)
    }

    /// Consumes the `Pin`, returns an [`InputPin`], sets its mode to [`Mode::Input`],
    /// and enables the pin's built-in pull-up resistor.
    ///
    /// The pull-up resistor is disabled when `InputPin` goes out of scope if [`reset_on_drop`]
    /// is set to `true` (default).
    ///
    /// [`InputPin`]: struct.InputPin.html
    /// [`Mode::Input`]: enum.Mode.html#variant.Input
    /// [`reset_on_drop`]: struct.InputPin.html#method.set_reset_on_drop
    #[inline]
    pub fn into_input_pullup(self) -> InputPin {
        InputPin::new(self, PullUp)
    }

    /// Consumes the pin, returns an [`OutputPin`] and sets its mode to [`Mode::Output`].
    ///
    /// [`OutputPin`]: struct.OutputPin.html
    /// [`Mode::Output`]: enum.Mode.html#variant.Output
    #[inline]
    pub fn into_output(self) -> OutputPin {
        OutputPin::new(self)
    }

    /// Consumes the pin, returns an [`AltPin`] and sets its mode to the given mode.
    ///
    /// [`AltPin`]: struct.AltPin.html
    /// [`Mode`]: enum.Mode.html
    #[inline]
    pub fn into_alt(self, mode: Mode) -> AltPin {
        AltPin::new(self, mode)
    }

    /// Returns the GPIO pin number.
    ///
    /// Pins are addressed by their BCM numbers, rather than their physical location.
    #[inline]
    pub fn pin(&self) -> u8 {
        self.pin
    }

    #[inline]
    pub(crate) fn set_mode(&mut self, mode: Mode) {
        self.gpio_state.gpio_mem.set_mode(self.pin, mode);
    }

    /// Returns the current GPIO pin mode.
    #[inline]
    pub fn mode(&self) -> Mode {
        self.gpio_state.gpio_mem.mode(self.pin)
    }

    /// Configures the built-in GPIO pull-up/pull-down resistors.
    #[inline]
    pub(crate) fn set_pullupdown(&self, pud: PullUpDown) {
        self.gpio_state.gpio_mem.set_pullupdown(self.pin, pud);
    }

    /// Reads the pin's current logic level.
    #[inline]
    pub fn read(&self) -> Level {
        self.gpio_state.gpio_mem.level(self.pin)
    }

    #[inline]
    pub(crate) fn set_low(&mut self) {
        self.gpio_state.gpio_mem.set_low(self.pin);
    }

    #[inline]
    pub(crate) fn set_high(&mut self) {
        self.gpio_state.gpio_mem.set_high(self.pin);
    }

    #[inline]
    pub(crate) fn write(&mut self, level: Level) {
        match level {
            Level::Low => self.set_low(),
            Level::High => self.set_high(),
        };
    }
}

impl Drop for Pin {
    fn drop(&mut self) {
        // Release taken pin
        self.gpio_state.pins_taken[self.pin as usize].store(false, Ordering::SeqCst);
    }
}

macro_rules! impl_pin {
    () => {
        /// Returns the GPIO pin number.
        ///
        /// Pins are addressed by their BCM numbers, rather than their physical location.
        #[inline]
        pub fn pin(&self) -> u8 {
            self.pin.pin
        }
    }
}

macro_rules! impl_input {
    () => {
        /// Reads the pin's current logic level.
        #[inline]
        pub fn read(&self) -> Level {
            self.pin.read()
        }

        /// Returns `true` if the pin's logic level is [`Level::Low`].
        ///
        /// [`Level::Low`]: enum.Level.html
        #[inline]
        pub fn is_low(&self) -> bool {
            self.pin.read() == Level::Low
        }

        /// Returns `true` if the pin's logic level is [`Level::High`].
        ///
        /// [`Level::High`]: enum.Level.html
        #[inline]
        pub fn is_high(&self) -> bool {
            self.pin.read() == Level::High
        }
    }
}

macro_rules! impl_output {
    () => {
        /// Sets pin's logic level to [`Level::Low`].
        ///
        /// [`Level::Low`]: enum.Level.html
        #[inline]
        pub fn set_low(&mut self) {
            self.pin.set_low()
        }

        /// Sets pin's logic level to [`Level::High`].
        ///
        /// [`Level::High`]: enum.Level.html
        #[inline]
        pub fn set_high(&mut self) {
            self.pin.set_high()
        }

        /// Sets pin's logic level.
        #[inline]
        pub fn write(&mut self, level: Level) {
            self.pin.write(level)
        }
    }
}

macro_rules! impl_reset_on_drop {
    () => {
        /// Returns the value of `reset_on_drop`.
        pub fn reset_on_drop(&self) -> bool {
            self.reset_on_drop
        }

        /// When enabled, resets the pin's mode to its original state and disables the
        /// built-in pull-up/pull-down resistors, when the pin goes out of scope.
        /// By default, this is set to `true`.
        ///
        /// # Note
        ///
        /// Drop methods aren't called when a program is abnormally terminated, for
        /// instance when a user presses <kbd>Ctrl + C</kbd>, and the `SIGINT` signal
        /// isn't caught. You catch those using crates such as [`simple_signal`].
        ///
        /// [`simple_signal`]: https://crates.io/crates/simple-signal
        pub fn set_reset_on_drop(&mut self, reset_on_drop: bool) {
            self.reset_on_drop = reset_on_drop;
        }
    };
}

macro_rules! impl_drop {
    ($struct:ident) => {
        impl Drop for $struct {
            /// Resets the pin's mode and built-in pull-up/pull-down resistors if
            /// `reset_on_drop` is set to `true` (default).
            fn drop(&mut self) {
                if !self.reset_on_drop {
                    return;
                }

                if let Some(prev_mode) = self.prev_mode {
                    self.pin.set_mode(prev_mode);
                }

                if self.pud_mode != Off {
                    self.pin.set_pullupdown(Off);
                }
            }
        }
    };
}

/// GPIO pin configured as input.
#[derive(Debug)]
pub struct InputPin {
    pub(crate) pin: Pin,
    prev_mode: Option<Mode>,
    async_interrupt: Option<AsyncInterrupt>,
    reset_on_drop: bool,
    pud_mode: PullUpDown,
}

impl InputPin {
    pub(crate) fn new(mut pin: Pin, pud_mode: PullUpDown) -> InputPin {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Input {
            None
        } else {
            pin.set_mode(Mode::Input);
            Some(prev_mode)
        };

        pin.set_pullupdown(pud_mode);

        InputPin {
            pin,
            prev_mode,
            async_interrupt: None,
            reset_on_drop: true,
            pud_mode,
        }
    }

    impl_pin!();
    impl_input!();

    /// Configures a synchronous interrupt trigger.
    ///
    /// After configuring a synchronous interrupt trigger, use [`poll_interrupt`] or
    /// [`Gpio::poll_interrupts`] to block while waiting for a trigger event.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`poll_interrupt`]: #method.poll_interrupt
    /// [`Gpio::poll_interrupts`]: struct.Gpio#method.poll_interrupts
    pub fn set_interrupt(&mut self, trigger: Trigger) -> Result<()> {
        self.clear_async_interrupt()?;

        // Each pin can only be configured for a single trigger type
        (*self.pin.gpio_state.sync_interrupts.lock().unwrap()).set_interrupt(self.pin(), trigger)
    }

    /// Removes a previously configured synchronous interrupt trigger.
    pub fn clear_interrupt(&mut self) -> Result<()> {
        (*self.pin.gpio_state.sync_interrupts.lock().unwrap()).clear_interrupt(self.pin())
    }

    /// Blocks until an interrupt is triggered on the pin, or a timeout occurs.
    ///
    /// This only works after the pin has been configured for synchronous interrupts using
    /// [`set_interrupt`]. Asynchronous interrupt triggers are automatically polled on a separate thread.
    ///
    /// Calling `poll_interrupt` blocks any other calls to `poll_interrupt` (including on other `InputPin`s) or
    /// [`Gpio::poll_interrupts`] until it returns. If you need to poll multiple pins simultaneously, use
    /// [`Gpio::poll_interrupts`] to block while waiting for any of the interrupts to trigger, or switch to
    /// using asynchronous interrupts with [`set_async_interrupt`].
    ///
    /// If `reset` is set to `false`, returns immediately if an interrupt trigger event was cached in a
    /// previous call to `poll_interrupt`.
    /// If `reset` is set to `true`, clears any cached interrupt trigger events before polling.
    ///
    /// The `timeout` duration indicates how long the call will block while waiting
    /// for interrupt trigger events, after which an `Ok(None))` is returned.
    /// `timeout` can be set to `None` to wait indefinitely.
    ///
    /// [`set_interrupt`]: #method.set_interrupt
    /// [`Gpio::poll_interrupts`]: struct.Gpio#method.poll_interrupts
    /// [`set_async_interrupt`]: #method.set_async_interrupt
    pub fn poll_interrupt(
        &mut self,
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<Option<Level>> {
        let opt =
            (*self.pin.gpio_state.sync_interrupts.lock().unwrap()).poll(&[self], reset, timeout)?;

        if let Some(trigger) = opt {
            Ok(Some(trigger.1))
        } else {
            Ok(None)
        }
    }

    /// Configures an asynchronous interrupt trigger, which will execute the callback on a
    /// separate thread when the interrupt is triggered.
    ///
    /// The callback closure or function pointer is called with a single [`Level`] argument.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`Level`]: enum.Level.html
    pub fn set_async_interrupt<C>(&mut self, trigger: Trigger, callback: C) -> Result<()>
    where
        C: FnMut(Level) + Send + 'static,
    {
        self.clear_interrupt()?;
        self.clear_async_interrupt()?;

        self.async_interrupt = Some(AsyncInterrupt::new(
            self.pin.gpio_state.cdev.as_raw_fd(),
            self.pin(),
            trigger,
            callback,
        )?);

        Ok(())
    }

    /// Removes a previously configured asynchronous interrupt trigger.
    pub fn clear_async_interrupt(&mut self) -> Result<()> {
        if let Some(mut interrupt) = self.async_interrupt.take() {
            interrupt.stop()?;
        }

        Ok(())
    }

    impl_reset_on_drop!();
}

impl_drop!(InputPin);

/// GPIO pin configured as output.
#[derive(Debug)]
pub struct OutputPin {
    pin: Pin,
    prev_mode: Option<Mode>,
    reset_on_drop: bool,
    pud_mode: PullUpDown,
}

impl OutputPin {
    pub(crate) fn new(mut pin: Pin) -> OutputPin {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Output {
            None
        } else {
            pin.set_mode(Mode::Output);
            Some(prev_mode)
        };

        OutputPin {
            pin,
            prev_mode,
            reset_on_drop: true,
            pud_mode: Off,
        }
    }

    impl_pin!();
    impl_input!();
    impl_output!();
    impl_reset_on_drop!();
}

impl_drop!(OutputPin);

/// GPIO pin configured with an alternate function.
#[derive(Debug)]
pub struct AltPin {
    pin: Pin,
    mode: Mode,
    prev_mode: Option<Mode>,
    reset_on_drop: bool,
    pud_mode: PullUpDown,
}

impl AltPin {
    pub(crate) fn new(mut pin: Pin, mode: Mode) -> AltPin {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == mode {
            None
        } else {
            pin.set_mode(mode);
            Some(prev_mode)
        };

        AltPin {
            pin,
            mode,
            prev_mode,
            reset_on_drop: true,
            pud_mode: Off,
        }
    }

    impl_pin!();
    impl_input!();
    impl_output!();
    impl_reset_on_drop!();
}

impl_drop!(AltPin);
<|endoftext|>


<commit_before>//! Defining things related to gradient computation.
use crate::op::{GradientContext, InputArray};
use crate::tensor::{Tensor, TensorInternal};
use crate::Float;
use crate::FxHashMap;
use crate::Graph;
use std::cell::UnsafeCell;
use std::cmp::Ordering;
use std::collections::binary_heap::BinaryHeap;

struct GradInfo<'a, 'b, T: Float + 'a> {
    has_gradient: bool,
    grad_called: bool,
    computed_grads: UnsafeCell<InputArray<Tensor<'b, T>>>,
    accumulated_grad: UnsafeCell<Option<Tensor<'b, T>>>,
    default_grad: Option<&'a TensorInternal<T>>,
}

impl<'t, 's, T: Float> GradInfo<'t, 's, T> {
    #[inline]
    fn new(has_gradient: bool, default_grad: Option<&'t TensorInternal<T>>) -> GradInfo<'t, 's, T> {
        GradInfo {
            has_gradient,
            computed_grads: UnsafeCell::new(InputArray::new()),
            grad_called: false,
            accumulated_grad: UnsafeCell::new(None),
            default_grad,
        }
    }

    #[inline]
    fn push_grad(&self, g: Tensor<'s, T>) {
        unsafe {
            (&mut *self.computed_grads.get()).push(g);
        }
    }

    fn accumulate_then_get(&self, s: &'s Graph<T>) -> Tensor<'s, T> {
        unsafe {
            if let Some(ret) = *self.accumulated_grad.get() {
                // accumulation completed
                ret
            } else {
                let before_acc = &*self.computed_grads.get();
                if before_acc.len() > 1 {
                    // accumulate
                    let accumulated = s.add_n(before_acc.as_slice());
                    *self.accumulated_grad.get() = Some(accumulated);
                    accumulated
                } else {
                    // accumulation is not required
                    before_acc[0]
                }
            }
        }
    }
}

#[inline]
fn has_marked_child<'a, 'b, T: Float>(
    s: &'b Graph<T>,
    parent: &TensorInternal<T>,
    path: &FxHashMap<usize, GradInfo<'a, 'b, T>>,
) -> bool {
    for child in parent.get_backprop_inputs().iter() {
        if path.get(&child.get(s).id()).unwrap().has_gradient {
            return true;
        }
    }
    false
}

#[inline]
fn is_wrt<T: Float>(node: &TensorInternal<T>, wrt: &[&TensorInternal<T>]) -> bool {
    wrt.contains(&node)
}

// Marks `has_gradient` if each node is on the gradient propagation path.
// Map keys of return value are tensor ids.
//
// Strategy
//   1. Record all nodes that are reachable from `ys` into `ret`.
//   2. Mark the path between `ys` and `xs` as `has_gradient`.
fn get_between_nodes<'a, 'b: 'a, T: Float>(
    s: &'b Graph<T>,
    ys: &[&'a TensorInternal<T>],
    wrt: &[&'a TensorInternal<T>],
) -> FxHashMap<usize, GradInfo<'a, 'b, T>> {
    // Randomly accessible by use of each node's lookup key.
    let mut ret = FxHashMap::<usize, GradInfo<T>>::default();

    // Builds GradInfo while performing depth-first-search.
    // `has_gradient` properties are filled at the same time.

    // dfs_stack: (node, should_visit)
    let mut dfs_stack: Vec<(&TensorInternal<T>, bool)> = ys.iter().map(|&y| (y, false)).collect();
    while let Some((node, should_visit)) = dfs_stack.pop() {
        if should_visit {
            let marker =
                node.is_differentiable && (is_wrt(node, wrt) || has_marked_child(s, node, &ret));
            ret.insert(node.id(), GradInfo::new(marker, None));
        } else {
            // Put self on the stack top (should visit next time)
            dfs_stack.push((node, true));
            // Push children as necessary
            for child in node.get_backprop_inputs() {
                let child = child.get(s);
                if ret.get(&node.id()).is_none() {
                    if child.is_source() || !child.is_differentiable() {
                        // Add to result, but don't allow any more recursive search
                        // because there will be no `wrt` nodes in this direction....
                        ret.insert(
                            child.id(),
                            GradInfo::new(
                                child.is_differentiable() && is_wrt(child.inner(), wrt),
                                None,
                            ),
                        );
                    } else {
                        // Recurse
                        dfs_stack.push((child.scoped_inner(), false));
                    }
                }
            }
        }
    }
    ret
}

/// Returns symbolic gradient tensors of `xs`.
///
/// This computes partial derivatives of `ys` with `xs` and returns the
/// gradients. This is achieved by building a subgraph between `ys` and
/// `xs` in reverse order from user's graph definition.
/// `gys` are already known gradients of `ys`'s outputs.
///
/// NOTE: Nodes that do not have gradients won't be included in the subgraph to avoid
/// unnecessary computation.
pub(crate) fn symbolic_gradients<'a, 'b, T: Float>(
    ys: &[&'a TensorInternal<T>],
    wrt: &[&'a TensorInternal<T>],
    gys: &[&'a TensorInternal<T>],
    g: &'b Graph<T>,
) -> Vec<Tensor<'b, T>> {
    assert_eq!(ys.len(), gys.len(), "`ys.len()` must match `gys.len()`");

    // Setup gradient path.
    // We lookup this with tensor id.
    let mut between_nodes = get_between_nodes(g, ys, wrt);

    // Set default grads.
    for (y, gy) in ys.iter().zip(gys) {
        between_nodes.get_mut(&y.id()).unwrap().default_grad = Some(gy);
    }

    // Prepare a heap with given ys.
    let mut heap = ys
        .iter()
        .map(|y| y.wrapped())
        .collect::<BinaryHeap<TensorWrapper<T>>>();

    // Backprop.
    // Starts with `ys`.
    while let Some(y) = heap.pop() {
        let gxs = {
            let info: &GradInfo<_> = between_nodes.get(&y.tsr.id()).unwrap();
            let gy = if let Some(def) = info.default_grad {
                g.scoped(def)
            } else {
                info.accumulate_then_get(g)
            };
            // Call Op::grad
            let mut ctx = GradientContext::new(gy, g.scoped(y.tsr), g);
            y.tsr.op.grad(&mut ctx);
            let gxs = ctx.extract_input_grads();
            debug_assert_eq!(y.tsr.in_edges.len(), gxs.len());
            gxs
        };
        // Register computed gradients
        let xs = y.tsr.get_backprop_inputs();
        for (gx, x) in gxs.into_iter().zip(xs) {
            let x = x.get(g);
            let mut x_info = between_nodes.get_mut(&x.id()).unwrap();
            if x_info.has_gradient {
                if let Some(gx) = gx {
                    x_info.push_grad(gx);
                    // update heap
                    if !x.is_source() && !x_info.grad_called {
                        x_info.grad_called = true;
                        heap.push(x.scoped_inner().wrapped());
                    }
                }
            }
        }
    }

    // Aggregate and return xs's gradients
    let mut ret = Vec::with_capacity(wrt.len());
    for x in wrt {
        let msg1: &str = "Not differentiable with given tensor(s).";
        let info = between_nodes.get(&x.id()).expect(msg1);
        if !info.has_gradient {
            panic!(msg1);
        }
        assert!(
            info.default_grad.is_none(),
            "Can't differentiate with objective itself"
        );
        ret.push(info.accumulate_then_get(g));
    }
    ret
}

struct TensorWrapper<'a, T: Float + 'a> {
    tsr: &'a TensorInternal<T>,
}

impl<'a, T: Float> Ord for TensorWrapper<'a, T> {
    // Compares the ranks in topological ordering
    fn cmp(&self, other: &Self) -> Ordering {
        self.tsr.top_rank.cmp(&other.tsr.top_rank)
    }
}

impl<'a, T: Float> PartialOrd for TensorWrapper<'a, T> {
    #[inline]
    // Compares the ranks in topological ordering
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.tsr.top_rank.cmp(&other.tsr.top_rank))
    }
}

impl<'a, T: Float> Eq for TensorWrapper<'a, T> {}

impl<'a, T: Float> PartialEq for TensorWrapper<'a, T> {
    #[inline]
    fn eq(&self, other: &TensorWrapper<'a, T>) -> bool {
        self.tsr.id() == other.tsr.id()
    }
}

impl<'a, T: Float> TensorInternal<T> {
    #[inline]
    fn wrapped(&'a self) -> TensorWrapper<'a, T> {
        TensorWrapper { tsr: self }
    }
}
<commit_msg>Refactor<commit_after>//! Defining things related to gradient computation.
use crate::op::{GradientContext, InputArray};
use crate::tensor::{Tensor, TensorInternal};
use crate::Float;
use crate::FxHashMap;
use crate::Graph;
use std::cell::UnsafeCell;
use std::cmp::Ordering;
use std::collections::binary_heap::BinaryHeap;

struct GradInfo<'a, 'b, T: Float + 'a> {
    has_gradient: bool,
    grad_called: bool,
    computed_grads: UnsafeCell<InputArray<Tensor<'b, T>>>,
    accumulated_grad: UnsafeCell<Option<Tensor<'b, T>>>,
    default_grad: Option<&'a TensorInternal<T>>,
}

impl<'t, 'g, T: Float> GradInfo<'t, 'g, T> {
    #[inline]
    fn new(has_gradient: bool, default_grad: Option<&'t TensorInternal<T>>) -> GradInfo<'t, 'g, T> {
        GradInfo {
            has_gradient,
            computed_grads: UnsafeCell::new(InputArray::new()),
            grad_called: false,
            accumulated_grad: UnsafeCell::new(None),
            default_grad,
        }
    }

    #[inline]
    fn push_grad(&self, g: Tensor<'g, T>) {
        unsafe {
            (&mut *self.computed_grads.get()).push(g);
        }
    }

    fn accumulate_then_get(&self, s: &'g Graph<T>) -> Tensor<'g, T> {
        unsafe {
            if let Some(ret) = *self.accumulated_grad.get() {
                // accumulation completed
                ret
            } else {
                let before_acc = &*self.computed_grads.get();
                if before_acc.len() > 1 {
                    // accumulate
                    let accumulated = s.add_n(before_acc.as_slice());
                    *self.accumulated_grad.get() = Some(accumulated);
                    accumulated
                } else {
                    // accumulation is not required
                    before_acc[0]
                }
            }
        }
    }
}

#[inline]
fn has_marked_child<'t, 'g, T: Float>(
    s: &'g Graph<T>,
    parent: &TensorInternal<T>,
    path: &FxHashMap<usize, GradInfo<'t, 'g, T>>,
) -> bool {
    for child in parent.get_backprop_inputs().iter() {
        if path.get(&child.get(s).id()).unwrap().has_gradient {
            return true;
        }
    }
    false
}

#[inline]
fn is_wrt<T: Float>(node: &TensorInternal<T>, wrt: &[&TensorInternal<T>]) -> bool {
    wrt.contains(&node)
}

// Marks `has_gradient` if each node is on the gradient propagation path.
// Map keys of return value are tensor ids.
//
// Strategy
//   1. Record all nodes that are reachable from `ys` into `ret`.
//   2. Mark the path between `ys` and `xs` as `has_gradient`.
fn get_between_nodes<'t, 'g, T: Float>(
    s: &'g Graph<T>,
    ys: &[&'t TensorInternal<T>],
    wrt: &[&'t TensorInternal<T>],
) -> FxHashMap<usize, GradInfo<'t, 'g, T>> {
    // Randomly accessible by use of each node's lookup key.
    let mut ret = FxHashMap::<usize, GradInfo<T>>::default();

    // Builds GradInfo while performing depth-first-search.
    // `has_gradient` properties are filled at the same time.

    // dfs_stack: (node, should_visit)
    let mut dfs_stack: Vec<(&TensorInternal<T>, bool)> = ys.iter().map(|&y| (y, false)).collect();
    while let Some((node, should_visit)) = dfs_stack.pop() {
        if should_visit {
            let marker =
                node.is_differentiable && (is_wrt(node, wrt) || has_marked_child(s, node, &ret));
            ret.insert(node.id(), GradInfo::new(marker, None));
        } else {
            // Put self on the stack top (should visit next time)
            dfs_stack.push((node, true));
            // Push children as necessary
            for child in node.get_backprop_inputs() {
                let child = child.get(s);
                if ret.get(&node.id()).is_none() {
                    if child.is_source() || !child.is_differentiable() {
                        // Add to result, but don't allow any more recursive search
                        // because there will be no `wrt` nodes in this direction....
                        ret.insert(
                            child.id(),
                            GradInfo::new(
                                child.is_differentiable() && is_wrt(child.inner(), wrt),
                                None,
                            ),
                        );
                    } else {
                        // Recurse
                        dfs_stack.push((child.scoped_inner(), false));
                    }
                }
            }
        }
    }
    ret
}

/// Returns symbolic gradient tensors of `xs`.
///
/// This computes partial derivatives of `ys` with `xs` and returns the
/// gradients. This is achieved by building a subgraph between `ys` and
/// `xs` in reverse order from user's graph definition.
/// `gys` are already known gradients of `ys`'s outputs.
///
/// NOTE: Nodes that do not have gradients won't be included in the subgraph to avoid
/// unnecessary computation.
pub(crate) fn symbolic_gradients<'t, 'g, T: Float>(
    ys: &[&'t TensorInternal<T>],
    wrt: &[&'t TensorInternal<T>],
    gys: &[&'t TensorInternal<T>],
    g: &'g Graph<T>,
) -> Vec<Tensor<'g, T>> {
    assert_eq!(ys.len(), gys.len(), "`ys.len()` must match `gys.len()`");

    // Setup gradient path.
    // We lookup this with tensor id.
    let mut between_nodes = get_between_nodes(g, ys, wrt);

    // Set default grads.
    for (y, gy) in ys.iter().zip(gys) {
        between_nodes.get_mut(&y.id()).unwrap().default_grad = Some(gy);
    }

    // Prepare a heap with given ys.
    let mut heap = ys
        .iter()
        .map(|y| y.wrapped())
        .collect::<BinaryHeap<TensorWrapper<T>>>();

    // Backprop.
    // Starts with `ys`.
    while let Some(y) = heap.pop() {
        let gxs = {
            let info: &GradInfo<_> = between_nodes.get(&y.tsr.id()).unwrap();
            let gy = if let Some(def) = info.default_grad {
                g.scoped(def)
            } else {
                info.accumulate_then_get(g)
            };
            // Call Op::grad
            let mut ctx = GradientContext::new(gy, g.scoped(y.tsr), g);
            y.tsr.op.grad(&mut ctx);
            let gxs = ctx.extract_input_grads();
            debug_assert_eq!(y.tsr.in_edges.len(), gxs.len());
            gxs
        };
        // Register computed gradients
        let xs = y.tsr.get_backprop_inputs();
        for (gx, x) in gxs.into_iter().zip(xs) {
            let x = x.get(g);
            let mut x_info = between_nodes.get_mut(&x.id()).unwrap();
            if x_info.has_gradient {
                if let Some(gx) = gx {
                    x_info.push_grad(gx);
                    // update heap
                    if !x.is_source() && !x_info.grad_called {
                        x_info.grad_called = true;
                        heap.push(x.scoped_inner().wrapped());
                    }
                }
            }
        }
    }

    // Aggregate and return xs's gradients
    let mut ret = Vec::with_capacity(wrt.len());
    for x in wrt {
        let msg1: &str = "Not differentiable with given tensor(s).";
        let info = between_nodes.get(&x.id()).expect(msg1);
        if !info.has_gradient {
            panic!(msg1);
        }
        assert!(
            info.default_grad.is_none(),
            "Can't differentiate with objective itself"
        );
        ret.push(info.accumulate_then_get(g));
    }
    ret
}

struct TensorWrapper<'t, T: Float + 't> {
    tsr: &'t TensorInternal<T>,
}

impl<'t, T: Float> Ord for TensorWrapper<'t, T> {
    // Compares the ranks in topological ordering
    fn cmp(&self, other: &Self) -> Ordering {
        self.tsr.top_rank.cmp(&other.tsr.top_rank)
    }
}

impl<'t, T: Float> PartialOrd for TensorWrapper<'t, T> {
    #[inline]
    // Compares the ranks in topological ordering
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.tsr.top_rank.cmp(&other.tsr.top_rank))
    }
}

impl<'t, T: Float> Eq for TensorWrapper<'t, T> {}

impl<'t, T: Float> PartialEq for TensorWrapper<'t, T> {
    #[inline]
    fn eq(&self, other: &TensorWrapper<'t, T>) -> bool {
        self.tsr.id() == other.tsr.id()
    }
}

impl<'t, T: Float> TensorInternal<T> {
    #[inline]
    fn wrapped(&'t self) -> TensorWrapper<'t, T> {
        TensorWrapper { tsr: self }
    }
}
<|endoftext|>


<commit_before>use redox::*;

use super::Mode;
use super::Mode::*;
use super::Editor;

pub fn exec(editor: &mut Editor, mode: &mut Mode, multiplier: &mut Option<u32>, last_change: &mut String, key_event: KeyEvent, window: &mut Window) {
    match (*mode, key_event.scancode) {
        (Insert, K_ESC) => {
            *mode = Normal;
        },
        (Insert, K_BKSP) => editor.backspace(window),
        (Insert, K_DEL) => editor.delete(window),
        (_, K_F5) => editor.reload(window),
        (_, K_F6) => editor.save(window),
        (_, K_HOME) => editor.offset = 0,
        (_, K_UP) => editor.up(),
        (_, K_LEFT) => editor.left(),
        (_, K_RIGHT) => editor.right(),
        (_, K_END) => editor.offset = editor.string.len(),
        (_, K_DOWN) => editor.down(),
        (m, _) => {
            let (no_mult, mut times) = match *multiplier {
                Some(n) => (false, n),
                None => (true, 1),
            };
            let mut is_none = false;

            match key_event.character {
                '0' if !no_mult => times *= 10,

                '1' if no_mult => times = 1,
                '1' => times = times * 10 + 1,

                '2' if no_mult => times = 2,
                '2' => times = times * 10 + 2,

                '3' if no_mult => times = 3,
                '3' => times = times * 10 + 3,

                '4' if no_mult => times = 4,
                '4' => times = times * 10 + 4,

                '5' if no_mult => times = 5,
                '5' => times = times * 10 + 5,

                '6' if no_mult => times = 6,
                '6' => times = times * 10 + 6,

                '7' if no_mult => times = 7,
                '7' => times = times * 10 + 7,

                '8' if no_mult => times = 8,
                '8' => times = times * 10 + 8,

                '9' if no_mult => times = 9,
                '9' => times = times * 10 + 9,
                _ => {
                    for _ in 0 .. times {
                        match (m, key_event.character) {
                            (Normal, 'i') => {
                                *mode = Insert;
                                *last_change = editor.string.clone();
                            },
                            (Normal, 'h') => editor.left(),
                            (Normal, 'l') => editor.right(),
                            (Normal, 'k') => editor.up(),
                            (Normal, 'j') => editor.down(),
                            (Normal, 'G') => editor.offset = editor.string.len(),
                            (Normal, 'a') => {
                                editor.right();
                                *mode = Insert;
                                *last_change = editor.string.clone();
                            },
                            (Normal, 'x') => editor.delete(window),
                            (Normal, 'X') => editor.backspace(window),
                            (Normal, 'u') => {
                                editor.offset = 0;
                                ::core::mem::swap(last_change, &mut editor.string);
                            },
                            (Normal, '$') => {
                                let mut new_offset = editor.string.len();
                                for i in editor.offset..editor.string.len() {
                                    match editor.string.as_bytes()[i] {
                                        0 => break,
                                        10 => {
                                            new_offset = i;
                                            break;
                                        }
                                        _ => (),
                                    }
                                }
                                editor.offset = new_offset;
                            },
                            (Normal, '0') => {

                                let mut new_offset = 0;
                                for i in 2..editor.offset {
                                    match editor.string.as_bytes()[editor.offset - i] {
                                        0 => break,
                                        10 => {
                                            new_offset = editor.offset - i + 1;
                                            break;
                                        }
                                        _ => (),
                                    }
                                }
                                editor.offset = new_offset;
                            },
                            (Insert, '\0') => (),
                            (Insert, _) => {
                                window.set_title(&format!("{}{}{}","Editor (", &editor.url, ") Changed"));
                                editor.string = editor.string[0 .. editor.offset].to_string() +
                                    &key_event.character.to_string() +
                                    &editor.string[editor.offset .. editor.string.len()];
                                editor.offset += 1;
                            },
                            _ => {},
                        }
                    }
                    is_none = true;
                }
            }

            if !is_none {
                *multiplier = Some(times);
            } else {
                *multiplier = None;
            }
        }
    }
}
<commit_msg>Add `o` command to editor<commit_after>use redox::*;

use super::Mode;
use super::Mode::*;
use super::Editor;

pub fn exec(editor: &mut Editor, mode: &mut Mode, multiplier: &mut Option<u32>, last_change: &mut String, key_event: KeyEvent, window: &mut Window) {
    match (*mode, key_event.scancode) {
        (Insert, K_ESC) => {
            *mode = Normal;
        },
        (Insert, K_BKSP) => editor.backspace(window),
        (Insert, K_DEL) => editor.delete(window),
        (_, K_F5) => editor.reload(window),
        (_, K_F6) => editor.save(window),
        (_, K_HOME) => editor.offset = 0,
        (_, K_UP) => editor.up(),
        (_, K_LEFT) => editor.left(),
        (_, K_RIGHT) => editor.right(),
        (_, K_END) => editor.offset = editor.string.len(),
        (_, K_DOWN) => editor.down(),
        (m, _) => {
            let (no_mult, mut times) = match *multiplier {
                Some(n) => (false, n),
                None => (true, 1),
            };
            let mut is_none = false;

            match key_event.character {
                '0' if !no_mult => times *= 10,

                '1' if no_mult => times = 1,
                '1' => times = times * 10 + 1,

                '2' if no_mult => times = 2,
                '2' => times = times * 10 + 2,

                '3' if no_mult => times = 3,
                '3' => times = times * 10 + 3,

                '4' if no_mult => times = 4,
                '4' => times = times * 10 + 4,

                '5' if no_mult => times = 5,
                '5' => times = times * 10 + 5,

                '6' if no_mult => times = 6,
                '6' => times = times * 10 + 6,

                '7' if no_mult => times = 7,
                '7' => times = times * 10 + 7,

                '8' if no_mult => times = 8,
                '8' => times = times * 10 + 8,

                '9' if no_mult => times = 9,
                '9' => times = times * 10 + 9,
                _ => {
                    for _ in 0 .. times {
                        match (m, key_event.character) {
                            (Normal, 'i') => {
                                *mode = Insert;
                                *last_change = editor.string.clone();
                            },
                            (Normal, 'h') => editor.left(),
                            (Normal, 'l') => editor.right(),
                            (Normal, 'k') => editor.up(),
                            (Normal, 'j') => editor.down(),
                            (Normal, 'G') => editor.offset = editor.string.len(),
                            (Normal, 'a') => {
                                editor.right();
                                *mode = Insert;
                                *last_change = editor.string.clone();
                            },
                            (Normal, 'x') => editor.delete(window),
                            (Normal, 'X') => editor.backspace(window),
                            (Normal, 'u') => {
                                editor.offset = 0;
                                ::core::mem::swap(last_change, &mut editor.string);
                            },
                            (Normal, 'o') => {
                                exec(editor, mode, multiplier, last_change, KeyEvent {
                                    character: '$',
                                    scancode: 0,
                                    pressed: true,
                                }, window);
                                exec(editor, mode, multiplier, last_change, KeyEvent {
                                    character: 'i',
                                    scancode: 0,
                                    pressed: true,
                                }, window);
                                exec(editor, mode, multiplier, last_change, KeyEvent {
                                    character: '\n',
                                    scancode: 0,
                                    pressed: true,
                                }, window);
                            },
                            (Normal, '$') => {
                                let mut new_offset = editor.string.len();
                                for i in editor.offset..editor.string.len() {
                                    match editor.string.as_bytes()[i] {
                                        0 => break,
                                        10 => {
                                            new_offset = i;
                                            break;
                                        }
                                        _ => (),
                                    }
                                }
                                editor.offset = new_offset;
                            },
                            (Normal, '0') => {

                                let mut new_offset = 0;
                                for i in 2..editor.offset {
                                    match editor.string.as_bytes()[editor.offset - i] {
                                        0 => break,
                                        10 => {
                                            new_offset = editor.offset - i + 1;
                                            break;
                                        }
                                        _ => (),
                                    }
                                }
                                editor.offset = new_offset;
                            },
                            (Insert, '\0') => (),
                            (Insert, _) => {
                                window.set_title(&format!("{}{}{}","Editor (", &editor.url, ") Changed"));
                                editor.string = editor.string[0 .. editor.offset].to_string() +
                                    &key_event.character.to_string() +
                                    &editor.string[editor.offset .. editor.string.len()];
                                editor.offset += 1;
                            },
                            _ => {},
                        }
                    }
                    is_none = true;
                }
            }

            if !is_none {
                *multiplier = Some(times);
            } else {
                *multiplier = None;
            }
        }
    }
}
<|endoftext|>