<commit_before>use utils::bigint::{M256, U256, U512};
use utils::gas::Gas;
use utils::address::Address;
use utils::opcode::Opcode;
use vm::{VM, Machine, Memory, Stack, PC, ExecutionError, ExecutionResult, Storage};
use std::cmp::{min, max};

const G_ZERO: usize = 0;
const G_BASE: usize = 2;
const G_VERYLOW: usize = 3;
const G_LOW: usize = 5;
const G_MID: usize = 8;
const G_HIGH: usize = 10;
const G_EXTCODE_DEFAULT: usize = 20;
const G_EXTCODE_EIP150: usize = 700;
const G_BALANCE_DEFAULT: usize = 20;
const G_BALANCE_EIP150: usize = 400;
const G_SLOAD_DEFAULT: usize = 50;
const G_SLOAD_EIP150: usize = 200;
const G_JUMPDEST: usize = 1;
const G_SSET: usize = 20000;
const G_SRESET: usize = 5000;
const R_SCLEAR: usize = 15000;
const R_SUICIDE: usize = 24000;
const G_SUICIDE_DEFAULT: usize = 0;
const G_SUICIDE_EIP150: usize = 5000;
const G_CREATE: usize = 32000;
const G_CODEDEPOSITE: usize = 200;
const G_CALL_DEFAULT: usize = 20;
const G_CALL_EIP150: usize = 700;
const G_CALLVALUE: usize = 9000;
const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_EXPBYTE_DEFAULT: usize = 10;
const G_EXPBYTE_EIP160: usize = 50;
const G_MEMORY: usize = 3;
const G_TXCREATE: usize = 32000;
const G_TXDATAZERO: usize = 4;
const G_TXDATANONZERO: usize = 68;
const G_TRANSACTION: usize = 21000;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
const G_SHA3: usize = 30;
const G_SHA3WORD: usize = 6;
const G_COPY: usize = 3;
const G_BLOCKHASH: usize = 20;

fn memory_cost(a: Gas) -> Gas {
    (Gas::from(G_MEMORY) * a + a * a / Gas::from(512u64)).into()
}

fn sstore_cost<M: Memory + Default,
               S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let index = machine.stack().peek(0)?;
    let value = machine.stack().peek(1)?;
    let address = machine.context.address;

    if value != M256::zero() && machine.account_state.storage(address)?.read(index)? == M256::zero() {
        Ok(G_SSET.into())
    } else {
        Ok(G_SRESET.into())
    }
}

fn call_cost<M: Memory + Default,
             S: Storage + Default>(machine: &Machine<M, S>, available_gas: Gas) -> ExecutionResult<Gas> {
    Ok(gascap_cost(machine, available_gas)? + extra_cost(machine)?)
}

fn callgas_cost<M: Memory + Default,
                S: Storage + Default>(machine: &Machine<M, S>, available_gas: Gas) -> ExecutionResult<Gas> {
    let val = machine.stack().peek(2)?;
    if val != M256::zero() {
        Ok(gascap_cost(machine, available_gas)? + G_CALLSTIPEND.into())
    } else {
        Ok(gascap_cost(machine, available_gas)?)
    }
}

fn gascap_cost<M: Memory + Default,
               S: Storage + Default>(machine: &Machine<M, S>, available_gas: Gas) -> ExecutionResult<Gas> {
    let base2 = machine.stack().peek(0)?.into();

    if available_gas >= extra_cost(machine)? {
        let base1 = available_gas - extra_cost(machine)?;
        Ok(min(base1 - base1 / Gas::from(64u64), base2))
    } else {
        Ok(base2)
    }
}

fn extra_cost<M: Memory + Default,
              S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    Ok(Gas::from(if machine.patch.eip150() { G_CALL_EIP150 } else { G_CALL_DEFAULT }) + xfer_cost(machine)? + new_cost(machine)?)
}

fn xfer_cost<M: Memory + Default,
             S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let val = machine.stack().peek(2)?;
    if val != M256::zero() {
        Ok(G_CALLVALUE.into())
    } else {
        Ok(Gas::zero())
    }
}

fn new_cost<M: Memory + Default,
            S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let address: Address = machine.stack().peek(1)?.into();
    if address == Address::default() {
        Ok(G_NEWACCOUNT.into())
    } else {
        Ok(Gas::zero())
    }
}

fn suicide_cost<M: Memory + Default,
                S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let address: Address = machine.stack().peek(0)?.into();
    Ok(Gas::from(if machine.patch.eip150() { G_SUICIDE_EIP150 } else { G_SUICIDE_DEFAULT }) + if address == Address::default() {
        Gas::from(G_NEWACCOUNT)
    } else {
        Gas::zero()
    })
}

#[derive(Clone, Copy, Debug)]
pub struct CostAggregrator(Gas);

impl CostAggregrator {
    pub fn active_memory_len(&self) -> M256 {
        self.0.into()
    }
}

impl Default for CostAggregrator {
    fn default() -> CostAggregrator {
        CostAggregrator(Gas::zero())
    }
}

fn memory_expand(current: Gas, from: Gas, len: Gas) -> Gas {
    if len == Gas::zero() {
        return current;
    }

    let rem = (from + len) % Gas::from(32u64);
    let new = if rem == Gas::zero() {
        (from + len) / Gas::from(32u64)
    } else {
        (from + len) / Gas::from(32u64) + Gas::from(1u64)
    };
    max(current, new)
}

fn memory_gas_cost<M: Memory + Default,
                   S: Storage + Default>(opcode: Opcode, machine: &Machine<M, S>,
                                          aggregrator: CostAggregrator)
                               -> ExecutionResult<(Gas, CostAggregrator)> {
    let ref stack = machine.stack();
    let ref memory = machine.memory();

    let current = aggregrator.0;
    let next = match opcode {
        Opcode::SHA3 | Opcode::RETURN | Opcode::LOG(_) => {
            let from: U256 = stack.peek(0)?.into();
            let len: U256 = stack.peek(1)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Opcode::CODECOPY | Opcode::CALLDATACOPY => {
            let from: U256 = stack.peek(0)?.into();
            let len: U256 = stack.peek(2)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Opcode::EXTCODECOPY => {
            let from: U256 = stack.peek(1)?.into();
            let len: U256 = stack.peek(3)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Opcode::MLOAD | Opcode::MSTORE => {
            let from: U256 = stack.peek(0)?.into();
            memory_expand(current, Gas::from(from), Gas::from(32u64))
        },
        Opcode::MSTORE8 => {
            let from: U256 = stack.peek(0)?.into();
            memory_expand(current, Gas::from(from), Gas::from(1u64))
        },
        Opcode::CREATE => {
            let from: U256 = stack.peek(1)?.into();
            let len: U256 = stack.peek(2)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        _ => {
            current
        }
    };
    Ok((memory_cost(next) - memory_cost(current), CostAggregrator(next)))
}

pub fn gas_cost<M: Memory + Default,
                S: Storage + Default>(opcode: Opcode, machine: &Machine<M, S>,
                                       aggregrator: CostAggregrator)
                            -> ExecutionResult<(Gas, CostAggregrator)> {
    let self_cost: Gas = match opcode {
        Opcode::CALL | Opcode::CALLCODE |
        Opcode::DELEGATECALL => call_cost(machine, machine.available_gas())?,
        Opcode::SUICIDE => suicide_cost(machine)?,
        Opcode::SSTORE => sstore_cost(machine)?,

        Opcode::SHA3 => {
            let len = machine.stack.peek(1)?;
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_SHA3) + Gas::from(G_SHA3WORD) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Opcode::LOG(v) => {
            let len = machine.stack.peek(1)?;
            (Gas::from(G_LOG) + Gas::from(G_LOGDATA) * Gas::from(len) + Gas::from(G_LOGTOPIC) * Gas::from(v)).into()
        },

        Opcode::EXTCODECOPY => {
            let len = machine.stack.peek(3)?;
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(if machine.patch.eip150() { G_EXTCODE_EIP150 } else { G_EXTCODE_DEFAULT }) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Opcode::CALLDATACOPY | Opcode::CODECOPY => {
            let len = machine.stack.peek(2)?;
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_VERYLOW) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Opcode::EXP => {
            if machine.stack.peek(1)? == M256::zero() {
                Gas::from(G_EXP)
            } else {
                Gas::from(G_EXP) + Gas::from(if machine.patch.eip160() { G_EXPBYTE_EIP160 } else { G_EXPBYTE_DEFAULT }) * (Gas::from(1u64) + Gas::from(machine.stack.peek(1)?.log2floor()) / Gas::from(8u64))
            }
        }

        Opcode::CREATE => G_CREATE.into(),
        Opcode::JUMPDEST => G_JUMPDEST.into(),
        Opcode::SLOAD => (if machine.patch.eip150() { G_SLOAD_EIP150 } else { G_SLOAD_DEFAULT }).into(),

        // W_zero
        Opcode::STOP | Opcode::RETURN
            => G_ZERO.into(),

        // W_base
        Opcode::ADDRESS | Opcode::ORIGIN | Opcode::CALLER |
        Opcode::CALLVALUE | Opcode::CALLDATASIZE |
        Opcode::CODESIZE | Opcode::GASPRICE | Opcode::COINBASE |
        Opcode::TIMESTAMP | Opcode::NUMBER | Opcode::DIFFICULTY |
        Opcode::GASLIMIT | Opcode::POP | Opcode::PC |
        Opcode::MSIZE | Opcode::GAS
            => G_BASE.into(),

        // W_verylow
        Opcode::ADD | Opcode::SUB | Opcode::NOT | Opcode::LT |
        Opcode::GT | Opcode::SLT | Opcode::SGT | Opcode::EQ |
        Opcode::ISZERO | Opcode::AND | Opcode::OR | Opcode::XOR |
        Opcode::BYTE | Opcode::CALLDATALOAD | Opcode::MLOAD |
        Opcode::MSTORE | Opcode::MSTORE8 | Opcode::PUSH(_) |
        Opcode::DUP(_) | Opcode::SWAP(_)
            => G_VERYLOW.into(),

        // W_low
        Opcode::MUL | Opcode::DIV | Opcode::SDIV | Opcode::MOD |
        Opcode::SMOD | Opcode::SIGNEXTEND
            => G_LOW.into(),

        // W_mid
        Opcode::ADDMOD | Opcode::MULMOD | Opcode::JUMP
            => G_MID.into(),

        // W_high
        Opcode::JUMPI => G_HIGH.into(),

        // W_extcode
        Opcode::EXTCODESIZE => (if machine.patch.eip150() { G_EXTCODE_EIP150 } else { G_EXTCODE_DEFAULT }).into(),

        Opcode::BALANCE => (if machine.patch.eip150() { G_BALANCE_EIP150 } else { G_BALANCE_DEFAULT }).into(),
        Opcode::BLOCKHASH => G_BLOCKHASH.into(),
        Opcode::INVALID => Gas::zero(),
    };
    let (memory_gas, agg) = memory_gas_cost(opcode, machine, aggregrator)?;
    Ok((self_cost + memory_gas, agg))
}

pub fn gas_refund<M: Memory + Default,
                  S: Storage + Default>(opcode: Opcode, machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    match opcode {
        Opcode::SSTORE => {
            let index = machine.stack().peek(0)?;
            let value = machine.stack().peek(1)?;
            let address = machine.context.address;

            if value == M256::zero() && machine.account_state.storage(address)?.read(index)? != M256::zero() {
                Ok(Gas::from(R_SCLEAR))
            } else {
                Ok(Gas::zero())
            }
        },
        Opcode::SUICIDE => {
            // TODO: check whether I_a belongs to A_s
            Ok(Gas::zero())
        },
        _ => Ok(Gas::zero())
    }
}
<commit_msg>Problem: G_CALL is wrong, and gascap should be handled in opcodes Solution: return gascap_cost zero<commit_after>use utils::bigint::{M256, U256, U512};
use utils::gas::Gas;
use utils::address::Address;
use utils::opcode::Opcode;
use vm::{VM, Machine, Memory, Stack, PC, ExecutionError, ExecutionResult, Storage};
use std::cmp::{min, max};

const G_ZERO: usize = 0;
const G_BASE: usize = 2;
const G_VERYLOW: usize = 3;
const G_LOW: usize = 5;
const G_MID: usize = 8;
const G_HIGH: usize = 10;
const G_EXTCODE_DEFAULT: usize = 20;
const G_EXTCODE_EIP150: usize = 700;
const G_BALANCE_DEFAULT: usize = 20;
const G_BALANCE_EIP150: usize = 400;
const G_SLOAD_DEFAULT: usize = 50;
const G_SLOAD_EIP150: usize = 200;
const G_JUMPDEST: usize = 1;
const G_SSET: usize = 20000;
const G_SRESET: usize = 5000;
const R_SCLEAR: usize = 15000;
const R_SUICIDE: usize = 24000;
const G_SUICIDE_DEFAULT: usize = 0;
const G_SUICIDE_EIP150: usize = 5000;
const G_CREATE: usize = 32000;
const G_CODEDEPOSITE: usize = 200;
const G_CALL_DEFAULT: usize = 40;
const G_CALL_EIP150: usize = 700;
const G_CALLVALUE: usize = 9000;
const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_EXPBYTE_DEFAULT: usize = 10;
const G_EXPBYTE_EIP160: usize = 50;
const G_MEMORY: usize = 3;
const G_TXCREATE: usize = 32000;
const G_TXDATAZERO: usize = 4;
const G_TXDATANONZERO: usize = 68;
const G_TRANSACTION: usize = 21000;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
const G_SHA3: usize = 30;
const G_SHA3WORD: usize = 6;
const G_COPY: usize = 3;
const G_BLOCKHASH: usize = 20;

fn memory_cost(a: Gas) -> Gas {
    (Gas::from(G_MEMORY) * a + a * a / Gas::from(512u64)).into()
}

fn sstore_cost<M: Memory + Default,
               S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let index = machine.stack().peek(0)?;
    let value = machine.stack().peek(1)?;
    let address = machine.context.address;

    if value != M256::zero() && machine.account_state.storage(address)?.read(index)? == M256::zero() {
        Ok(G_SSET.into())
    } else {
        Ok(G_SRESET.into())
    }
}

fn call_cost<M: Memory + Default,
             S: Storage + Default>(machine: &Machine<M, S>, available_gas: Gas) -> ExecutionResult<Gas> {
    Ok(gascap_cost(machine, available_gas)? + extra_cost(machine)?)
}

fn callgas_cost<M: Memory + Default,
                S: Storage + Default>(machine: &Machine<M, S>, available_gas: Gas) -> ExecutionResult<Gas> {
    let val = machine.stack().peek(2)?;
    if val != M256::zero() {
        Ok(gascap_cost(machine, available_gas)? + G_CALLSTIPEND.into())
    } else {
        Ok(gascap_cost(machine, available_gas)?)
    }
}

fn gascap_cost<M: Memory + Default,
               S: Storage + Default>(machine: &Machine<M, S>, available_gas: Gas) -> ExecutionResult<Gas> {
    // let base2 = machine.stack().peek(0)?.into();

    // if available_gas >= extra_cost(machine)? {
    //     let base1 = available_gas - extra_cost(machine)?;
    //     Ok(min(base1 - base1 / Gas::from(64u64), base2))
    // } else {
    //     Ok(base2)
    // }
    Ok(Gas::zero())
}

fn extra_cost<M: Memory + Default,
              S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    Ok(Gas::from(if machine.patch.eip150() { G_CALL_EIP150 } else { G_CALL_DEFAULT }) + xfer_cost(machine)? + new_cost(machine)?)
}

fn xfer_cost<M: Memory + Default,
             S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let val = machine.stack().peek(2)?;
    if val != M256::zero() {
        Ok(G_CALLVALUE.into())
    } else {
        Ok(Gas::zero())
    }
}

fn new_cost<M: Memory + Default,
            S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let address: Address = machine.stack().peek(1)?.into();
    if address == Address::default() {
        Ok(G_NEWACCOUNT.into())
    } else {
        Ok(Gas::zero())
    }
}

fn suicide_cost<M: Memory + Default,
                S: Storage + Default>(machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    let address: Address = machine.stack().peek(0)?.into();
    Ok(Gas::from(if machine.patch.eip150() { G_SUICIDE_EIP150 } else { G_SUICIDE_DEFAULT }) + if address == Address::default() {
        Gas::from(G_NEWACCOUNT)
    } else {
        Gas::zero()
    })
}

#[derive(Clone, Copy, Debug)]
pub struct CostAggregrator(Gas);

impl CostAggregrator {
    pub fn active_memory_len(&self) -> M256 {
        self.0.into()
    }
}

impl Default for CostAggregrator {
    fn default() -> CostAggregrator {
        CostAggregrator(Gas::zero())
    }
}

fn memory_expand(current: Gas, from: Gas, len: Gas) -> Gas {
    if len == Gas::zero() {
        return current;
    }

    let rem = (from + len) % Gas::from(32u64);
    let new = if rem == Gas::zero() {
        (from + len) / Gas::from(32u64)
    } else {
        (from + len) / Gas::from(32u64) + Gas::from(1u64)
    };
    max(current, new)
}

fn memory_gas_cost<M: Memory + Default,
                   S: Storage + Default>(opcode: Opcode, machine: &Machine<M, S>,
                                          aggregrator: CostAggregrator)
                               -> ExecutionResult<(Gas, CostAggregrator)> {
    let ref stack = machine.stack();
    let ref memory = machine.memory();

    let current = aggregrator.0;
    let next = match opcode {
        Opcode::SHA3 | Opcode::RETURN | Opcode::LOG(_) => {
            let from: U256 = stack.peek(0)?.into();
            let len: U256 = stack.peek(1)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Opcode::CODECOPY | Opcode::CALLDATACOPY => {
            let from: U256 = stack.peek(0)?.into();
            let len: U256 = stack.peek(2)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Opcode::EXTCODECOPY => {
            let from: U256 = stack.peek(1)?.into();
            let len: U256 = stack.peek(3)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Opcode::MLOAD | Opcode::MSTORE => {
            let from: U256 = stack.peek(0)?.into();
            memory_expand(current, Gas::from(from), Gas::from(32u64))
        },
        Opcode::MSTORE8 => {
            let from: U256 = stack.peek(0)?.into();
            memory_expand(current, Gas::from(from), Gas::from(1u64))
        },
        Opcode::CREATE => {
            let from: U256 = stack.peek(1)?.into();
            let len: U256 = stack.peek(2)?.into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        _ => {
            current
        }
    };
    Ok((memory_cost(next) - memory_cost(current), CostAggregrator(next)))
}

pub fn gas_cost<M: Memory + Default,
                S: Storage + Default>(opcode: Opcode, machine: &Machine<M, S>,
                                       aggregrator: CostAggregrator)
                            -> ExecutionResult<(Gas, CostAggregrator)> {
    let self_cost: Gas = match opcode {
        Opcode::CALL | Opcode::CALLCODE |
        Opcode::DELEGATECALL => call_cost(machine, machine.available_gas())?,
        Opcode::SUICIDE => suicide_cost(machine)?,
        Opcode::SSTORE => sstore_cost(machine)?,

        Opcode::SHA3 => {
            let len = machine.stack.peek(1)?;
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_SHA3) + Gas::from(G_SHA3WORD) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Opcode::LOG(v) => {
            let len = machine.stack.peek(1)?;
            (Gas::from(G_LOG) + Gas::from(G_LOGDATA) * Gas::from(len) + Gas::from(G_LOGTOPIC) * Gas::from(v)).into()
        },

        Opcode::EXTCODECOPY => {
            let len = machine.stack.peek(3)?;
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(if machine.patch.eip150() { G_EXTCODE_EIP150 } else { G_EXTCODE_DEFAULT }) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Opcode::CALLDATACOPY | Opcode::CODECOPY => {
            let len = machine.stack.peek(2)?;
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            (Gas::from(G_VERYLOW) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }).into()
        },

        Opcode::EXP => {
            if machine.stack.peek(1)? == M256::zero() {
                Gas::from(G_EXP)
            } else {
                Gas::from(G_EXP) + Gas::from(if machine.patch.eip160() { G_EXPBYTE_EIP160 } else { G_EXPBYTE_DEFAULT }) * (Gas::from(1u64) + Gas::from(machine.stack.peek(1)?.log2floor()) / Gas::from(8u64))
            }
        }

        Opcode::CREATE => G_CREATE.into(),
        Opcode::JUMPDEST => G_JUMPDEST.into(),
        Opcode::SLOAD => (if machine.patch.eip150() { G_SLOAD_EIP150 } else { G_SLOAD_DEFAULT }).into(),

        // W_zero
        Opcode::STOP | Opcode::RETURN
            => G_ZERO.into(),

        // W_base
        Opcode::ADDRESS | Opcode::ORIGIN | Opcode::CALLER |
        Opcode::CALLVALUE | Opcode::CALLDATASIZE |
        Opcode::CODESIZE | Opcode::GASPRICE | Opcode::COINBASE |
        Opcode::TIMESTAMP | Opcode::NUMBER | Opcode::DIFFICULTY |
        Opcode::GASLIMIT | Opcode::POP | Opcode::PC |
        Opcode::MSIZE | Opcode::GAS
            => G_BASE.into(),

        // W_verylow
        Opcode::ADD | Opcode::SUB | Opcode::NOT | Opcode::LT |
        Opcode::GT | Opcode::SLT | Opcode::SGT | Opcode::EQ |
        Opcode::ISZERO | Opcode::AND | Opcode::OR | Opcode::XOR |
        Opcode::BYTE | Opcode::CALLDATALOAD | Opcode::MLOAD |
        Opcode::MSTORE | Opcode::MSTORE8 | Opcode::PUSH(_) |
        Opcode::DUP(_) | Opcode::SWAP(_)
            => G_VERYLOW.into(),

        // W_low
        Opcode::MUL | Opcode::DIV | Opcode::SDIV | Opcode::MOD |
        Opcode::SMOD | Opcode::SIGNEXTEND
            => G_LOW.into(),

        // W_mid
        Opcode::ADDMOD | Opcode::MULMOD | Opcode::JUMP
            => G_MID.into(),

        // W_high
        Opcode::JUMPI => G_HIGH.into(),

        // W_extcode
        Opcode::EXTCODESIZE => (if machine.patch.eip150() { G_EXTCODE_EIP150 } else { G_EXTCODE_DEFAULT }).into(),

        Opcode::BALANCE => (if machine.patch.eip150() { G_BALANCE_EIP150 } else { G_BALANCE_DEFAULT }).into(),
        Opcode::BLOCKHASH => G_BLOCKHASH.into(),
        Opcode::INVALID => Gas::zero(),
    };
    let (memory_gas, agg) = memory_gas_cost(opcode, machine, aggregrator)?;
    Ok((self_cost + memory_gas, agg))
}

pub fn gas_refund<M: Memory + Default,
                  S: Storage + Default>(opcode: Opcode, machine: &Machine<M, S>) -> ExecutionResult<Gas> {
    match opcode {
        Opcode::SSTORE => {
            let index = machine.stack().peek(0)?;
            let value = machine.stack().peek(1)?;
            let address = machine.context.address;

            if value == M256::zero() && machine.account_state.storage(address)?.read(index)? != M256::zero() {
                Ok(Gas::from(R_SCLEAR))
            } else {
                Ok(Gas::zero())
            }
        },
        Opcode::SUICIDE => {
            // TODO: check whether I_a belongs to A_s
            Ok(Gas::zero())
        },
        _ => Ok(Gas::zero())
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
use test::Bencher;

extern crate polylabel;
use polylabel::polylabel;

extern crate geo;
use self::geo::{Point, LineString, Polygon};

#[bench]
fn bench_threads(b: &mut Bencher) {
    let coords = vec![
        (-75.57274028771249, 110.01960141091608),
        (-47.01425001453319, 224.2535625036333),
        (-44.1986052400443, 233.56520178444188),
        (-40.491516848197264, 242.55919851821028),
        (-35.928066677809895, 251.1504384831045),
        (-30.55144070299677, 259.2576189250935),
        (-24.412520344941953, 266.8040179623472),
        (-17.56940095820731, 273.7182206387879),
        (-10.086842048356445, 279.93479475582495),
        (-2.0356544237308825, 285.394910086574),
        (6.507969918963688, 290.0468951126591),
        (15.463178833668529, 293.8467260149487),
        (24.745225165064543, 296.758443290685),
        (34.26626874888323, 298.7544920543751),
        (43.93620768274765, 299.8159828020204),
        (53.66353100085455, 299.9328701709592),
        (63.35618468325523, 299.10404800363494),
        (72.92244280430123, 297.33735981566144),
        (82.27177557618647, 294.64952456911897),
        (91.31570607290114, 291.0659784535237),
        (99.96864752703414, 286.6206341717666),
        (108.14871327570971, 281.355560009008),
        (115.77849169077639, 275.3205817216414),
        (122.78577875973701, 268.57281101383126),
        (129.10426138467784, 261.17610506386103),
        (134.67414493283295, 253.20046221503722),
        (139.44271909999156, 244.72135954999587),
        (189.4427190999916, 144.72135954999578),
        (193.40316487178438, 135.7190256296874),
        (196.46014848027284, 126.37119176608674),
        (198.5841005952538, 116.76827688896145),
        (199.75447683394128, 107.00316725394137),
        (199.959956480919, 97.1703179802708),
        (199.19855199019082, 87.36483941339068),
        (197.47762821014587, 77.68157714970485),
        (194.8138311454814, 68.21419462218802),
        (191.23292694514913, 59.05426712072333),
        (186.76955267374814, 50.29039601045239),
        (181.46688127708177, 42.007351716050565),
        (175.37620398257155, 34.28525376159651),
        (168.5564341738489, 27.198795797276006),
        (161.07353753840516, 20.81652310901589),
        (152.99989400031805, 15.200169599491232),
        (98.33653286253586, -18.964431111622638),
        (97.01425001453319, -24.253562503633297),
        (94.16983504461093, -33.64583432864707),
        (90.41851308474087, -42.71407837639184),
        (85.79641141607766, -51.37096249948156),
        (80.34804340438832, -59.53311617147662),
        (74.12587981200636, -67.12193339062866),
        (67.189843475707, -74.06432969864774),
        (59.606732217031976, -80.2934460239878),
        (51.44957554275259, -85.74929257125446),
        (42.79693133079759, -90.37932655572841),
        (33.73212927494458, -94.13895821910516),
        (24.342468374316272, -96.99198025324264),
        (14.718376196296493, -98.91091649633165),
        (4.952538009623515, -99.87728654335396),
        (-4.860995825414805, -99.88178372248515),
        (-14.627715613363762, -98.92436472343178),
        (-17.953756809330994, -98.26435835897965),
        (-53.64820903700594, -226.76438637860946),
        (-56.7355378616229, -236.07963555856995),
        (-60.72105444017349, -245.0474181249662),
        (-65.5663760693013, -253.58136942939535),
        (-71.22483965299563, -261.59930285566344),
        (-77.64195109371464, -269.02400132182726),
        (-84.75591010033425, -275.7839609229046),
        (-92.49820535873518, -281.81407955256725),
        (-100.79427433320987, -287.05628387201347),
        (-109.56422134444159, -291.46008858796654),
        (-118.72358700857137, -294.98308265364733),
        (-128.18416162723517, -297.59133771033885),
        (-137.85483469517902, -299.2597348360279),
        (-147.64247234423098, -299.9722064543555),
        (-157.4528142733637, -299.72189107416057),
        (-167.19138152692128, -298.5111993693906),
        (-176.76438637860946, -296.3517909629941),
        (-186.0796355585698, -293.26446213837716),
        (-195.04741812496607, -289.2789455598266),
        (-203.58136942939524, -284.4336239306988),
        (-211.59930285566332, -278.7751603470045),
        (-219.02400132182714, -272.3580489062855),
        (-225.78396092290453, -265.2440898996658),
        (-231.8140795525672, -257.50179464126495),
        (-237.0562838720134, -249.20572566679022),
        (-241.46008858796648, -240.4357786555585),
        (-244.98308265364727, -231.27641299142869),
        (-247.59133771033882, -221.8158383727649),
        (-249.25973483602792, -212.145165304821),
        (-249.97220645435553, -202.35752765576902),
        (-249.72189107416057, -192.54718572663626),
        (-248.51119936939062, -182.8086184730787),
        (-246.35179096299407, -173.23561362139054),
        (-196.35179096299407, 6.7643863786094585),
        (-193.32576660256726, 15.920764023655508),
        (-189.43184924301974, 24.74309266215056),
        (-184.7062507874361, 33.14932810051302),
        (-179.19291744665992, 41.0612956486063),
        (-172.94312105678188, 48.40541711367358),
        (-166.01498227118805, 55.11339504865113),
        (-158.47293006129595, 61.12284789161923),
        (-150.3871025524086, 66.37789008984335),
        (-75.57274028771249, 110.01960141091608)];
    let ls = LineString(coords.iter().map(|e| Point::new(e.0, e.1)).collect());
    let poly = Polygon(ls, vec![]);
    b.iter(||{
        polylabel(
            &poly,
            &10.0
        );
    });
}
<commit_msg>Smaller benchmark<commit_after>#![feature(test)]

extern crate test;
use test::Bencher;

extern crate polylabel;
use polylabel::polylabel;

extern crate geo;
use self::geo::{Point, LineString, Polygon};

#[bench]
fn bench_threads(b: &mut Bencher) {
    // an L shape
    let coords = vec![(0.0, 0.0), (4.0, 0.0), (4.0, 1.0), (1.0, 1.0), (1.0, 4.0), (0.0, 4.0),
                      (0.0, 0.0)];
    let ls = LineString(coords.iter().map(|e| Point::new(e.0, e.1)).collect());
    let poly = Polygon::new(ls, vec![]);
    b.iter(|| { polylabel(&poly, &10.0); });
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate time;
extern crate fruently;

#[cfg(test)]
mod tests {
    use test;
    use test::Bencher;
    use time;
    use fruently::fluent::Fluent;
    use std::collections::HashMap;

    #[bench]
    fn benchmark_json_forwardable(b: &mut Bencher) {
        use fruently::forwardable::JsonForwardable;

        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("name".to_string(), "fruently".to_string());
        b.iter(|| {
            let fruently = Fluent::new("0.0.0.0:24224", "test");
            let _ = fruently.post(&obj);
        });
    }

    #[bench]
    fn benchmark_msgpack_forwardable(b: &mut Bencher) {
        use fruently::forwardable::MsgpackForwardable;

        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("name".to_string(), "fruently".to_string());
        b.iter(|| {
            let fruently = Fluent::new("0.0.0.0:24224", "test");
            let _ = fruently.post(&obj);
        });
    }

    #[bench]
    fn benchmark_forwardable(b: &mut Bencher) {
        use fruently::forwardable::Forwardable;

        let mut obj = HashMap::new();
        let time = time::now().to_timespec().sec;
        b.iter(|| {
            let n = test::black_box(1000);
            let hmap = (0..n).fold(&mut obj, |mut acc, _| {
                {
                    acc.insert("fwd", "fruently".to_string());
                }
                acc
            });
            let entry = (time, &*hmap);
            let fruently = Fluent::new("0.0.0.0:24224", "test");
            let _ = fruently.post(vec![(entry)]);
        })
    }
}
<commit_msg>bench: Fix encodable records' key names<commit_after>#![feature(test)]

extern crate test;
extern crate time;
extern crate fruently;

#[cfg(test)]
mod tests {
    use test;
    use test::Bencher;
    use time;
    use fruently::fluent::Fluent;
    use std::collections::HashMap;

    #[bench]
    fn benchmark_json_forwardable(b: &mut Bencher) {
        use fruently::forwardable::JsonForwardable;

        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("json".to_string(), "fruently".to_string());
        b.iter(|| {
            let fruently = Fluent::new("0.0.0.0:24224", "test");
            let _ = fruently.post(&obj);
        });
    }

    #[bench]
    fn benchmark_msgpack_forwardable(b: &mut Bencher) {
        use fruently::forwardable::MsgpackForwardable;

        let mut obj: HashMap<String, String> = HashMap::new();
        obj.insert("msgp".to_string(), "fruently".to_string());
        b.iter(|| {
            let fruently = Fluent::new("0.0.0.0:24224", "test");
            let _ = fruently.post(&obj);
        });
    }

    #[bench]
    fn benchmark_forwardable(b: &mut Bencher) {
        use fruently::forwardable::Forwardable;

        let mut obj = HashMap::new();
        let time = time::now().to_timespec().sec;
        b.iter(|| {
            let n = test::black_box(1000);
            let hmap = (0..n).fold(&mut obj, |mut acc, _| {
                {
                    acc.insert("fwd", "fruently".to_string());
                }
                acc
            });
            let entry = (time, &*hmap);
            let fruently = Fluent::new("0.0.0.0:24224", "test");
            let _ = fruently.post(vec![(entry)]);
        })
    }
}
<|endoftext|>


<commit_before>use rodio::Sink;
use app;
use app::App;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use rodio::Source;
use rodio::Sample;

pub struct Dj {
    sink: Sink,
    id: u64,
    drop: bool,
    game_object_listener_id: u64,
    component_listener_id: i32,
}

impl Dj {
    pub fn id(&self) -> u64 {
        self.id
    }

    pub fn drop(&mut self) {
        self.drop = true;
    }

    pub fn set_idle_listener(&mut self, game_object_id: u64, component_id: i32) {
        self.game_object_listener_id = game_object_id;
        self.component_listener_id = component_id;
    }

    pub fn play(&mut self) {
        self.sink.play();
    }

    pub fn pause(&mut self) {
        self.sink.pause();
    }

    pub fn is_paused(&self) -> bool {
        self.sink.is_paused()
    }

    pub fn set_volume(&mut self, volume: f32) {
        self.sink.set_volume(volume);
    }

    pub fn volume(&self) -> f32 {
        self.sink.volume()
    }

    pub fn queue(&mut self, app: &mut App, path: &str) {
        let sound_over = Arc::new(AtomicBool::new(false));
        self.sink.append(app::fetch_sound(app, path));
    }

    pub fn is_over(&self) -> bool {
        self.sink.is_empty()
    }
}

pub fn was_dropped(dj: &Dj) -> bool {
    dj.drop
}

pub fn get_listener(dj: &Dj) -> (u64, i32) {
    (dj.game_object_listener_id, dj.component_listener_id)
}

pub fn new_dj(sink: Sink, app: &mut App) -> Dj {
    Dj {
        sink: sink,
        id: app::next_dj_id(app),
        drop: false,
        game_object_listener_id: 0,
        component_listener_id: 0,
    }
}
<commit_msg>Remove unused Arc<AtomicBool><commit_after>use rodio::Sink;
use app;
use app::App;

pub struct Dj {
    sink: Sink,
    id: u64,
    drop: bool,
    game_object_listener_id: u64,
    component_listener_id: i32,
}

impl Dj {
    pub fn id(&self) -> u64 {
        self.id
    }

    pub fn drop(&mut self) {
        self.drop = true;
    }

    pub fn set_idle_listener(&mut self, game_object_id: u64, component_id: i32) {
        self.game_object_listener_id = game_object_id;
        self.component_listener_id = component_id;
    }

    pub fn play(&mut self) {
        self.sink.play();
    }

    pub fn pause(&mut self) {
        self.sink.pause();
    }

    pub fn is_paused(&self) -> bool {
        self.sink.is_paused()
    }

    pub fn set_volume(&mut self, volume: f32) {
        self.sink.set_volume(volume);
    }

    pub fn volume(&self) -> f32 {
        self.sink.volume()
    }

    pub fn queue(&mut self, app: &mut App, path: &str) {
        self.sink.append(app::fetch_sound(app, path));
    }

    pub fn is_over(&self) -> bool {
        self.sink.is_empty()
    }
}

pub fn was_dropped(dj: &Dj) -> bool {
    dj.drop
}

pub fn get_listener(dj: &Dj) -> (u64, i32) {
    (dj.game_object_listener_id, dj.component_listener_id)
}

pub fn new_dj(sink: Sink, app: &mut App) -> Dj {
    Dj {
        sink: sink,
        id: app::next_dj_id(app),
        drop: false,
        game_object_listener_id: 0,
        component_listener_id: 0,
    }
}
<|endoftext|>


<commit_before><commit_msg>Another test<commit_after><|endoftext|>


<commit_before>//! Handles example propagation.

use rsmt2::print::Expr2Smt ;

use common::* ;
use data::{ Data, Sample } ;

/// Result of trying to force a sample positive/negative.
pub enum ForceRes {
  /// Failure.
  None,
  /// Sample was classified as positive.
  Pos { sample: Sample, clause: ClsIdx },
  /// Sample was classified as negative.
  Neg { sample: Sample, clause: ClsIdx },
}

/// Propagates examples, tries to break implication constraints.
pub struct Assistant {
  /// Core, to communicate with the teacher.
  // core: & 'a MsgCore,
  /// Solver.
  solver: Solver<()>,
  /// Instance.
  instance: Arc<Instance>,
  /// Positive constraints.
  pos: PrdHMap< ClsSet >,
  /// Negative constraints.
  neg: PrdHMap< ClsSet >,
  /// Profiler.
  _profiler: Profiler,
  /// True if we're using ADTs.
  using_adts: bool,
}

impl Assistant {

  /// Constructor.
  pub fn new(
    instance: Arc<Instance>, // core: & 'a MsgCore
  ) -> Res<Self> {
    let solver = conf.solver.spawn(
      "assistant", (), & instance
    ) ? ;
    let _profiler = Profiler::new() ;

    let mut pos = PrdHMap::with_capacity( instance.preds().len() ) ;
    let mut neg = PrdHMap::with_capacity( instance.preds().len() ) ;

    let mut pos_clauses = ClsSet::new() ;
    let mut neg_clauses = ClsSet::new() ;

    let using_adts = dtyp::get_all().iter().next().is_some() ;

    macro_rules! add_clauses {
      ($pred:expr) => ({
        if ! pos_clauses.is_empty() {
          let mut clause_set = ClsSet::new() ;
          ::std::mem::swap( & mut pos_clauses, & mut clause_set ) ;
          let prev = pos.insert($pred, clause_set) ;
          debug_assert! { prev.is_none() }
        }
        if ! neg_clauses.is_empty() {
          let mut clause_set = ClsSet::new() ;
          ::std::mem::swap( & mut neg_clauses, & mut clause_set ) ;
          let prev = neg.insert($pred, clause_set) ;
          debug_assert! { prev.is_none() }
        }
      }) ;
    }

    for pred in instance.pred_indices() {
      debug_assert! { pos_clauses.is_empty() }
      debug_assert! { neg_clauses.is_empty() }

      for clause in instance.clauses_of(pred).1 {
        let clause = * clause ;
        if instance[clause].lhs_preds().is_empty() {
          let is_new = pos_clauses.insert(clause) ;
          debug_assert! { is_new }
        }
      }

      for clause in instance.clauses_of(pred).0 {
        let clause = * clause ;
        if instance[clause].rhs().is_none()
        && instance[clause].lhs_pred_apps_len() == 1 {
          let is_new = neg_clauses.insert(clause) ;
          debug_assert! { is_new }
        }
      }

      add_clauses!(pred)
    }

    Ok(
      Assistant {
        // core,
        solver, instance, pos, neg, _profiler, using_adts
      }
    )
  }

  /// Destroys the assistant.
  pub fn finalize(mut self) -> Res<Profiler> {
    self.solver.kill().chain_err(
      || "While killing solver"
    ) ? ;
    Ok(self._profiler)
  }

  /// Breaks implications.
  pub fn break_implications(
    & mut self, data: & mut Data
  ) -> Res<()> {
    if data.constraints.is_empty() { return Ok(()) }

    let (mut pos, mut neg) = ( Vec::new(), Vec::new() ) ;
    // msg! { debug self.core => "breaking implications..." }
    profile! { self "constraints received" => add data.constraints.len() }

    'all_constraints: for cstr in CstrRange::zero_to(
      data.constraints.len()
    ) {

      // Can happen because of simplifications when propagating.
      if cstr > data.constraints.len() {
        break
      }
      if data.constraints[cstr].is_tautology() {
        continue
      }

      // debug! {
      //   "  {}", data.constraints[cstr].string_do(
      //     self.instance.preds(), |s| s.to_string()
      //   ).unwrap()
      // }

      let mut trivial = false ;
      let mut rhs_false = false ;
      let mut lhs_unknown = 0 ;
      macro_rules! move_on {
        (if trivial) => ( if trivial { move_on!() } ) ;
        () => ({
          if trivial
          || lhs_unknown == 0
          || rhs_false && lhs_unknown == 1 {
            profile! { self "constraints   broken" => add 1 }
          }
          // Discard the constraint, regardless of what will happen.
          profile! { self tick "data" }
          data.tautologize(cstr) ? ;
          for (Sample { pred, args }, clause) in pos.drain(0..) {
            data.add_pos(clause, pred, args) ;
          }
          for (Sample { pred, args }, clause) in neg.drain(0..) {
            data.add_neg(clause, pred, args) ;
          }
          data.propagate() ? ;
          profile! { self mark "data" }
          continue 'all_constraints
        }) ;
      }

      if let Some(
        & Sample { pred, ref args }
      ) = data.constraints[cstr].rhs() {
        match self.try_force(data, pred, args) ? {
          ForceRes::None => (),
          ForceRes::Pos { sample, clause } => {
            pos.push( (sample, clause) ) ;
            // Constraint is trivial, move on.
            trivial = true
          },
          ForceRes::Neg { sample, clause } => {
            rhs_false = true ;
            neg.push( (sample, clause) )
          },
        }
      }

      // move_on!(if trivial) ;

      if let Some(lhs) = data.constraints[cstr].lhs() {
        for (pred, samples) in lhs {
          let mut lhs_trivial = true ;
          for sample in samples {
            match self.try_force(data, * pred, sample) ? {
              ForceRes::None => {
                lhs_unknown += 1 ;
                lhs_trivial = false
              },
              ForceRes::Pos { sample, clause } => pos.push(
                (sample, clause)
              ),
              ForceRes::Neg { sample, clause } => {
                neg.push( (sample, clause) ) ;
                trivial = true ;
                // Constraint is trivial, move on.
                // break 'lhs
              },
            }
          }
          trivial = trivial || lhs_trivial
        }
      } else {
        bail!("Illegal constraint")
      }

      move_on!()

    }

    let (_pos_count, _neg_count) = data.pos_neg_count() ;
    if ! data.pos.is_empty() {
      profile! { self "positive examples generated" => add _pos_count }
    }
    if ! data.neg.is_empty() {
      profile! { self "negative examples generated" => add _neg_count }
    }

    Ok(())
  }

  /// Checks if a sample can be forced to anything.
  ///
  /// If it can't, return None. If it can, returns
  ///
  /// - `ForceRes::Pos` of a sample which, when forced positive, will force the
  ///   input sample to be classified positive.
  /// - `ForceRes::Neg` of a sample which, when forced negative, will force the
  ///   input sample to be classified negative.
  pub fn try_force(
    & mut self, _data: & Data, pred: PrdIdx, vals: & VarVals
  ) -> Res<ForceRes> {
    self.solver.comment_args(
      format_args!("working on sample ({} {})", self.instance[pred], vals)
    ) ? ;

    if let Some(clauses) = self.pos.get(& pred) {

      self.solver.comment("working on positive clauses") ? ;

      for clause_idx in clauses {
        let clause_idx = * clause_idx ;
        let clause = & self.instance[clause_idx] ;
        if let Some((p, args)) = clause.rhs() {
          debug_assert_eq! { pred, p }
          debug_assert! { clause.lhs_preds().is_empty() }

          if self.using_adts {
            smt::reset(& mut self.solver, & self.instance) ?
          } else {
            self.solver.push(1) ?
          }

          clause.declare(& mut self.solver) ? ;
          self.solver.assert(
            & ConjWrap::new( clause.lhs_terms() )
          ) ? ;

          self.solver.assert( & ArgValEq::new(args, vals) ) ? ;
          let sat = profile! {
            self wrap {
              self.solver.check_sat() ?
            } "smt"
          } ;

          if ! self.using_adts {
            self.solver.pop(1) ?
          }

          if sat {
            // msg! { debug self => "  forcing positive" }
            return Ok(
              ForceRes::Pos {
                sample: Sample { pred, args: vals.clone() },
                clause: clause_idx,
              }
            )
          }
        } else {
          bail!("inconsistent instance state")
        }
      }

    }

    if let Some(clauses) = self.neg.get(& pred) {

      self.solver.comment("working on negative clauses") ? ;

      for clause_idx in clauses {
        let clause_idx = * clause_idx ;
        let clause = & self.instance[clause_idx] ;
        if let Some(argss) = clause.lhs_preds().get(& pred) {
          let args = {
            let mut argss = argss.iter() ;
            if let Some(args) = argss.next() {
              debug_assert! { argss.next().is_none() }
              args
            } else {
              bail!("inconsistent instance state")
            }
          } ;

          self.solver.push(1) ? ;
          clause.declare(& mut self.solver) ? ;
          self.solver.assert(
            & ConjWrap::new( clause.lhs_terms() )
          ) ? ;
          self.solver.assert( & ArgValEq::new(args, vals) ) ? ;
          let sat = profile! {
            self wrap {
              self.solver.check_sat() ?
            } "smt"
          } ;
          self.solver.pop(1) ? ;

          if sat {
            // msg! { debug self => "  forcing negative" }
            return Ok(
              ForceRes::Neg {
                sample: Sample { pred, args: vals.clone() },
                clause: clause_idx,
              }
            )
          }
        } else {
          bail!("inconsistent instance state")
        }
      }

    }

    Ok(ForceRes::None)
  }

}

/// Wrapper around a conjunction for smt printing.
struct ConjWrap<'a> {
  /// Conjunction.
  terms: & 'a TermSet,
}
impl<'a> ConjWrap<'a> {
  /// Constructor.
  pub fn new(terms: & 'a TermSet) -> Self {
    ConjWrap { terms }
  }
}
impl<'a> ::rsmt2::print::Expr2Smt<()> for ConjWrap<'a> {
  fn expr_to_smt2<Writer: Write>(
    & self, w: & mut Writer, _: ()
  ) -> SmtRes<()> {
    if self.terms.is_empty() {
      write!(w, "true") ?
    } else {
      write!(w, "(and") ? ;
      for term in self.terms {
        write!(w, " ") ? ;
        term.write(w, |w, var| var.default_write(w)) ? ;
      }
      write!(w, ")") ?
    }
    Ok(())
  }
}

/// Wrapper around some arguments and some values.
///
/// Used to assert `(= arg[i] val[i])`.
pub struct ArgValEq<'a> {
  /// Arguments.
  args: & 'a VarTerms,
  /// Values.
  vals: & 'a VarVals,
}
impl<'a> ArgValEq<'a> {
  /// Constructor.
  pub fn new(args: & 'a VarTerms, vals: & 'a VarVals) -> Self {
    debug_assert_eq! { args.len(), vals.len() }
    ArgValEq { args, vals }
  }
}
impl<'a> Expr2Smt<()> for ArgValEq<'a> {
  fn expr_to_smt2<Writer>(
    & self, w: & mut Writer, _: ()
  ) -> ::rsmt2::SmtRes<()>
  where Writer: Write {
    write!(w, "(and") ? ;
    let mut unknown = 0 ;

    for (arg, val) in self.args.iter().zip( self.vals.iter() ) {
      if ! val.is_known() {
        unknown += 1 ;
        continue
      }

      match val.get() {
        val::RVal::B(b) => {
          write!(w, " ") ? ;
          if ! b {
            write!(w, "(not ") ?
          }
          arg.write(
            w, |w, v| w.write_all( v.default_str().as_bytes() )
          ) ? ;
          if ! b {
            write!(w, ")") ?
          }
        },

        val::RVal::I(ref i) => {
          write!(w, " (= ") ? ;
          arg.write(
            w, |w, v| w.write_all( v.default_str().as_bytes() )
          ) ? ;
          write!(w, " ") ? ;
          int_to_smt!(w, i) ? ;
          write!(w, ")") ?
        },

        val::RVal::R(ref r) => {
          write!(w, " (= ") ? ;
          arg.write(
            w, |w, v| w.write_all( v.default_str().as_bytes() )
          ) ? ;
          write!(w, " ") ? ;
          rat_to_smt!(w, r) ? ;
          write!(w, ")") ?
        },

        val::RVal::Array { .. } |
        val::RVal::DTypNew { .. } => {
          write!(w, " (= ") ? ;
          arg.write(
            w, |w, v| w.write_all( v.default_str().as_bytes() )
          ) ? ;
          write!(w, " {})", val) ?
        },

        val::RVal::N(_) => (),
      }
    }

    if unknown == self.args.len() {
      write!(w, " true") ?
    }
    write!(w, ")") ? ;
    Ok(())
  }

}
<commit_msg>assistant fix<commit_after>//! Handles example propagation.

use rsmt2::print::Expr2Smt ;

use common::* ;
use data::{ Data, Sample } ;

/// Result of trying to force a sample positive/negative.
pub enum ForceRes {
  /// Failure.
  None,
  /// Sample was classified as positive.
  Pos { sample: Sample, clause: ClsIdx },
  /// Sample was classified as negative.
  Neg { sample: Sample, clause: ClsIdx },
}

/// Propagates examples, tries to break implication constraints.
pub struct Assistant {
  /// Core, to communicate with the teacher.
  // core: & 'a MsgCore,
  /// Solver.
  solver: Solver<()>,
  /// Instance.
  instance: Arc<Instance>,
  /// Positive constraints.
  pos: PrdHMap< ClsSet >,
  /// Negative constraints.
  neg: PrdHMap< ClsSet >,
  /// Profiler.
  _profiler: Profiler,
  /// True if we're using ADTs.
  using_adts: bool,
}

impl Assistant {

  /// Constructor.
  pub fn new(
    instance: Arc<Instance>, // core: & 'a MsgCore
  ) -> Res<Self> {
    let solver = conf.solver.spawn(
      "assistant", (), & instance
    ) ? ;
    let _profiler = Profiler::new() ;

    let mut pos = PrdHMap::with_capacity( instance.preds().len() ) ;
    let mut neg = PrdHMap::with_capacity( instance.preds().len() ) ;

    let mut pos_clauses = ClsSet::new() ;
    let mut neg_clauses = ClsSet::new() ;

    let using_adts = dtyp::get_all().iter().next().is_some() ;

    macro_rules! add_clauses {
      ($pred:expr) => ({
        if ! pos_clauses.is_empty() {
          let mut clause_set = ClsSet::new() ;
          ::std::mem::swap( & mut pos_clauses, & mut clause_set ) ;
          let prev = pos.insert($pred, clause_set) ;
          debug_assert! { prev.is_none() }
        }
        if ! neg_clauses.is_empty() {
          let mut clause_set = ClsSet::new() ;
          ::std::mem::swap( & mut neg_clauses, & mut clause_set ) ;
          let prev = neg.insert($pred, clause_set) ;
          debug_assert! { prev.is_none() }
        }
      }) ;
    }

    for pred in instance.pred_indices() {
      debug_assert! { pos_clauses.is_empty() }
      debug_assert! { neg_clauses.is_empty() }

      for clause in instance.clauses_of(pred).1 {
        let clause = * clause ;
        if instance[clause].lhs_preds().is_empty() {
          let is_new = pos_clauses.insert(clause) ;
          debug_assert! { is_new }
        }
      }

      for clause in instance.clauses_of(pred).0 {
        let clause = * clause ;
        if instance[clause].rhs().is_none()
        && instance[clause].lhs_pred_apps_len() == 1 {
          let is_new = neg_clauses.insert(clause) ;
          debug_assert! { is_new }
        }
      }

      add_clauses!(pred)
    }

    Ok(
      Assistant {
        // core,
        solver, instance, pos, neg, _profiler, using_adts
      }
    )
  }

  /// Destroys the assistant.
  pub fn finalize(mut self) -> Res<Profiler> {
    self.solver.kill().chain_err(
      || "While killing solver"
    ) ? ;
    Ok(self._profiler)
  }

  /// Breaks implications.
  pub fn break_implications(
    & mut self, data: & mut Data
  ) -> Res<()> {
    if data.constraints.is_empty() { return Ok(()) }

    let (mut pos, mut neg) = ( Vec::new(), Vec::new() ) ;
    // msg! { debug self.core => "breaking implications..." }
    profile! { self "constraints received" => add data.constraints.len() }

    'all_constraints: for cstr in CstrRange::zero_to(
      data.constraints.len()
    ) {

      // Can happen because of simplifications when propagating.
      if cstr > data.constraints.len() {
        break
      }
      if data.constraints[cstr].is_tautology() {
        continue
      }

      // debug! {
      //   "  {}", data.constraints[cstr].string_do(
      //     self.instance.preds(), |s| s.to_string()
      //   ).unwrap()
      // }

      let mut trivial = false ;
      let mut rhs_false = false ;
      let mut lhs_unknown = 0 ;
      macro_rules! move_on {
        (if trivial) => ( if trivial { move_on!() } ) ;
        () => ({
          if trivial
          || lhs_unknown == 0
          || rhs_false && lhs_unknown == 1 {
            profile! { self "constraints   broken" => add 1 }
          }
          // Discard the constraint, regardless of what will happen.
          profile! { self tick "data" }
          data.tautologize(cstr) ? ;
          for (Sample { pred, args }, clause) in pos.drain(0..) {
            data.add_pos(clause, pred, args) ;
          }
          for (Sample { pred, args }, clause) in neg.drain(0..) {
            data.add_neg(clause, pred, args) ;
          }
          data.propagate() ? ;
          profile! { self mark "data" }
          continue 'all_constraints
        }) ;
      }

      if let Some(
        & Sample { pred, ref args }
      ) = data.constraints[cstr].rhs() {
        match self.try_force(data, pred, args) ? {
          ForceRes::None => (),
          ForceRes::Pos { sample, clause } => {
            pos.push( (sample, clause) ) ;
            // Constraint is trivial, move on.
            trivial = true
          },
          ForceRes::Neg { sample, clause } => {
            rhs_false = true ;
            neg.push( (sample, clause) )
          },
        }
      }

      // move_on!(if trivial) ;

      if let Some(lhs) = data.constraints[cstr].lhs() {
        for (pred, samples) in lhs {
          let mut lhs_trivial = true ;
          for sample in samples {
            match self.try_force(data, * pred, sample) ? {
              ForceRes::None => {
                lhs_unknown += 1 ;
                lhs_trivial = false
              },
              ForceRes::Pos { sample, clause } => pos.push(
                (sample, clause)
              ),
              ForceRes::Neg { sample, clause } => {
                neg.push( (sample, clause) ) ;
                trivial = true ;
                // Constraint is trivial, move on.
                // break 'lhs
              },
            }
          }
          trivial = trivial || lhs_trivial
        }
      } else {
        bail!("Illegal constraint")
      }

      move_on!()

    }

    let (_pos_count, _neg_count) = data.pos_neg_count() ;
    if ! data.pos.is_empty() {
      profile! { self "positive examples generated" => add _pos_count }
    }
    if ! data.neg.is_empty() {
      profile! { self "negative examples generated" => add _neg_count }
    }

    Ok(())
  }

  /// Checks if a sample can be forced to anything.
  ///
  /// If it can't, return None. If it can, returns
  ///
  /// - `ForceRes::Pos` of a sample which, when forced positive, will force the
  ///   input sample to be classified positive.
  /// - `ForceRes::Neg` of a sample which, when forced negative, will force the
  ///   input sample to be classified negative.
  pub fn try_force(
    & mut self, _data: & Data, pred: PrdIdx, vals: & VarVals
  ) -> Res<ForceRes> {
    self.solver.comment_args(
      format_args!("working on sample ({} {})", self.instance[pred], vals)
    ) ? ;

    if let Some(clauses) = self.pos.get(& pred) {

      self.solver.comment("working on positive clauses") ? ;

      for clause_idx in clauses {
        let clause_idx = * clause_idx ;
        let clause = & self.instance[clause_idx] ;
        if let Some((p, args)) = clause.rhs() {
          debug_assert_eq! { pred, p }
          debug_assert! { clause.lhs_preds().is_empty() }

          if self.using_adts {
            smt::reset(& mut self.solver, & self.instance) ?
          } else {
            self.solver.push(1) ?
          }

          clause.declare(& mut self.solver) ? ;
          self.solver.assert(
            & ConjWrap::new( clause.lhs_terms() )
          ) ? ;

          self.solver.assert( & ArgValEq::new(args, vals) ) ? ;
          let sat = profile! {
            self wrap {
              self.solver.check_sat() ?
            } "smt"
          } ;

          if self.using_adts {
            smt::reset(& mut self.solver, & self.instance) ?
          } else {
            self.solver.pop(1) ?
          }

          if sat {
            // msg! { debug self => "  forcing positive" }
            return Ok(
              ForceRes::Pos {
                sample: Sample { pred, args: vals.clone() },
                clause: clause_idx,
              }
            )
          }
        } else {
          bail!("inconsistent instance state")
        }
      }

    }

    if let Some(clauses) = self.neg.get(& pred) {

      self.solver.comment("working on negative clauses") ? ;

      for clause_idx in clauses {
        let clause_idx = * clause_idx ;
        let clause = & self.instance[clause_idx] ;
        if let Some(argss) = clause.lhs_preds().get(& pred) {
          let args = {
            let mut argss = argss.iter() ;
            if let Some(args) = argss.next() {
              debug_assert! { argss.next().is_none() }
              args
            } else {
              bail!("inconsistent instance state")
            }
          } ;

          if self.using_adts {
            smt::reset(& mut self.solver, & self.instance) ?
          } else {
            self.solver.push(1) ?
          }

          clause.declare(& mut self.solver) ? ;
          self.solver.assert(
            & ConjWrap::new( clause.lhs_terms() )
          ) ? ;
          self.solver.assert( & ArgValEq::new(args, vals) ) ? ;
          let sat = profile! {
            self wrap {
              self.solver.check_sat() ?
            } "smt"
          } ;

          if self.using_adts {
            smt::reset(& mut self.solver, & self.instance) ?
          } else {
            self.solver.pop(1) ?
          }

          if sat {
            // msg! { debug self => "  forcing negative" }
            return Ok(
              ForceRes::Neg {
                sample: Sample { pred, args: vals.clone() },
                clause: clause_idx,
              }
            )
          }
        } else {
          bail!("inconsistent instance state")
        }
      }

    }

    Ok(ForceRes::None)
  }

}

/// Wrapper around a conjunction for smt printing.
struct ConjWrap<'a> {
  /// Conjunction.
  terms: & 'a TermSet,
}
impl<'a> ConjWrap<'a> {
  /// Constructor.
  pub fn new(terms: & 'a TermSet) -> Self {
    ConjWrap { terms }
  }
}
impl<'a> ::rsmt2::print::Expr2Smt<()> for ConjWrap<'a> {
  fn expr_to_smt2<Writer: Write>(
    & self, w: & mut Writer, _: ()
  ) -> SmtRes<()> {
    if self.terms.is_empty() {
      write!(w, "true") ?
    } else {
      write!(w, "(and") ? ;
      for term in self.terms {
        write!(w, " ") ? ;
        term.write(w, |w, var| var.default_write(w)) ? ;
      }
      write!(w, ")") ?
    }
    Ok(())
  }
}

/// Wrapper around some arguments and some values.
///
/// Used to assert `(= arg[i] val[i])`.
pub struct ArgValEq<'a> {
  /// Arguments.
  args: & 'a VarTerms,
  /// Values.
  vals: & 'a VarVals,
}
impl<'a> ArgValEq<'a> {
  /// Constructor.
  pub fn new(args: & 'a VarTerms, vals: & 'a VarVals) -> Self {
    debug_assert_eq! { args.len(), vals.len() }
    ArgValEq { args, vals }
  }
}
impl<'a> Expr2Smt<()> for ArgValEq<'a> {
  fn expr_to_smt2<Writer>(
    & self, w: & mut Writer, _: ()
  ) -> ::rsmt2::SmtRes<()>
  where Writer: Write {
    write!(w, "(and") ? ;
    let mut unknown = 0 ;

    for (arg, val) in self.args.iter().zip( self.vals.iter() ) {
      if ! val.is_known() {
        unknown += 1 ;
        continue
      }

      match val.get() {
        val::RVal::B(b) => {
          write!(w, " ") ? ;
          if ! b {
            write!(w, "(not ") ?
          }
          arg.write(
            w, |w, v| w.write_all( v.default_str().as_bytes() )
          ) ? ;
          if ! b {
            write!(w, ")") ?
          }
        },

        val::RVal::I(ref i) => {
          write!(w, " (= ") ? ;
          arg.write(
            w, |w, v| w.write_all( v.default_str().as_bytes() )
          ) ? ;
          write!(w, " ") ? ;
          int_to_smt!(w, i) ? ;
          write!(w, ")") ?
        },

        val::RVal::R(ref r) => {
          write!(w, " (= ") ? ;
          arg.write(
            w, |w, v| w.write_all( v.default_str().as_bytes() )
          ) ? ;
          write!(w, " ") ? ;
          rat_to_smt!(w, r) ? ;
          write!(w, ")") ?
        },

        val::RVal::Array { .. } |
        val::RVal::DTypNew { .. } => {
          write!(w, " (= ") ? ;
          arg.write(
            w, |w, v| w.write_all( v.default_str().as_bytes() )
          ) ? ;
          write!(w, " {})", val) ?
        },

        val::RVal::N(_) => (),
      }
    }

    if unknown == self.args.len() {
      write!(w, " true") ?
    }
    write!(w, ")") ? ;
    Ok(())
  }

}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::{IResult,digit};

use std::str;
use std::str::FromStr;

named!(float <f32>, map_res!(
  map_res!(
    recognize!(
      alt!(
        delimited!(digit, tag!("."), opt!(digit)) |
        delimited!(opt!(digit), tag!("."), digit)
      )
    ),
    str::from_utf8
  ),
  FromStr::from_str
));

#[test]
fn float_test() {
  assert_eq!(float(&b"123.456"[..]), IResult::Done(&b""[..], 123.456));
  assert_eq!(float(&b"0.123"[..]),   IResult::Done(&b""[..], 0.123));
  assert_eq!(float(&b"123.0"[..]),   IResult::Done(&b""[..], 123.0));
  assert_eq!(float(&b"123."[..]),    IResult::Done(&b""[..], 123.0));
  assert_eq!(float(&b".123"[..]),    IResult::Done(&b""[..], 0.123));
}
<commit_msg>float: rename to unsigned_float, add example signed float parser<commit_after>#[macro_use]
extern crate nom;

use nom::{IResult,digit};

use std::str;
use std::str::FromStr;

named!(unsigned_float <f32>, map_res!(
  map_res!(
    recognize!(
      alt!(
        delimited!(digit, tag!("."), opt!(digit)) |
        delimited!(opt!(digit), tag!("."), digit)
      )
    ),
    str::from_utf8
  ),
  FromStr::from_str
));

named!(float <f32>, map!(
  pair!(
    opt!(alt!(tag!("+") | tag!("-"))),
    unsigned_float
  ),
  |(sign, value): (Option<&[u8]>, f32)| {
    sign.and_then(|s| if s[0] == ('-' as u8) { Some(-1f32) } else { None }).unwrap_or(1f32) * value
  }
));

#[test]
fn unsigned_float_test() {
  assert_eq!(unsigned_float(&b"123.456"[..]), IResult::Done(&b""[..], 123.456));
  assert_eq!(unsigned_float(&b"0.123"[..]),   IResult::Done(&b""[..], 0.123));
  assert_eq!(unsigned_float(&b"123.0"[..]),   IResult::Done(&b""[..], 123.0));
  assert_eq!(unsigned_float(&b"123."[..]),    IResult::Done(&b""[..], 123.0));
  assert_eq!(unsigned_float(&b".123"[..]),    IResult::Done(&b""[..], 0.123));
}

#[test]
fn float_test() {
  assert_eq!(float(&b"123.456"[..]),  IResult::Done(&b""[..], 123.456));
  assert_eq!(float(&b"+123.456"[..]), IResult::Done(&b""[..], 123.456));
  assert_eq!(float(&b"-123.456"[..]), IResult::Done(&b""[..], -123.456));
}
<|endoftext|>


<commit_before>//! LossyCounter implementation.

use std::collections::hash_map::{Entry, HashMap};
use std::hash::Hash;

#[derive(Clone, Debug)]
struct KnownEntry {
    f: usize,
    delta: usize,
}

/// A LossyCounter is a data structure that memorizes the most frequent elements in data stream.
///
/// # Examples
/// ```
/// use pdatastructs::topk::lossycounter::LossyCounter;
///
/// // set up filter
/// let epsilon = 0.01;  // error threshold
/// let mut lc = LossyCounter::with_properties(epsilon);
///
/// // add some data
/// for i in 0..1000 {
///     let x = i % 10;
///     let y = if x < 4 {
///         0
///     } else if x < 7 {
///         1
///     } else {
///         x
///     };
///     lc.add(y);
/// }
///
/// // later
/// let threshold = 0.2;
/// let mut elements: Vec<u64> = lc.query(threshold).collect();
/// elements.sort();  // normalize order for testing purposes
/// assert_eq!(elements, vec![0, 1]);
/// ```
///
/// # Applications
/// - getting a fixed number of most common example of a large data set
/// - detect hotspots / very common events
///
/// # How It Works
/// The LossyCounter is initialized with an relative error bound `epsilon`. Depending on that, a
/// window size will be set. A window is the number of elements after which the counter will be
/// pruned.
///
/// ## Insertion
/// If the element is unknown (i.e. it was never seen before or was already pruned), it will be
/// stored with a frequency of 1. Also, the current window index will be stored alongside.
///
/// ```text
/// window size    = 4
///
///
/// insert(a):
///              n = 1
/// current window = 1
///
/// +---------+-------+-----------+
/// | element | delta | frequency |
/// +=========+=======+===========+
/// |       a |     0 |         1 |  <-- inserted
/// +---------+-------+-----------+
///
///
/// insert(b):
///              n = 2
/// current window = 1
///
/// +---------+-------+-----------+
/// | element | delta | frequency |
/// +=========+=======+===========+
/// |       a |     0 |         1 |
/// |       b |     0 |         1 |  <-- inserted
/// +---------+-------+-----------+
/// ```
///
/// If the element is know, the counter will be increased by 1.
///
/// ```text
/// window size    = 4
///
///
/// insert(a):
///              n = 3
/// current window = 1
///
/// +---------+-------+-----------+
/// | element | delta | frequency |
/// +=========+=======+===========+
/// |       a |     0 |         2 |  <-- incremented
/// |       b |     0 |         1 |
/// +---------+-------+-----------+
///
///
/// insert(a):
///              n = 4
/// current window = 1
///
/// +---------+-------+-----------+
/// | element | delta | frequency |
/// +=========+=======+===========+
/// |       a |     0 |         3 |  <-- incremented
/// |       b |     0 |         1 |
/// +---------+-------+-----------+
/// ```
///
/// If the window ends, pruning takes place. Elements will only be kept if their recorded frequency
/// plus the window index stored with them (i.e. the index they where recorded first) is at least
/// as large as the current window index. So elements that where not seen for a while will slowly
/// be kicked out of the counter, hence the name "Lossy Counter". In other words: an element will
/// only stay in the counter if it was seen more often than the number of windows since it was
/// inserted (i.e. number of windows plus 1).
///
/// ```text
/// window size    = 4
///
///
/// prune:
///              n = 4
/// current window = 1
///
/// +---------+-------+-----------+
/// | element | delta | frequency |
/// +=========+=======+===========+
/// |       a |     0 |         2 |
/// |       b |     0 |         1 |  <-- remove
/// +---------+-------+-----------+
///
/// +---------+-------+-----------+
/// | element | delta | frequency |
/// +=========+=======+===========+
/// |       a |     0 |         2 |
/// +---------+-------+-----------+
/// ```
///
/// ## Query
/// Given a relative threshold, all elements will be returned for which the following holds:
///
/// ```text
/// f >= (threshold - epsilon) * n
/// ```
///
/// # See Also
/// - `std::collections::HashSet`: has a false positive rate of 0%, but also needs to store all
///   elements
/// - `pdatastructs::topk::cmsheap::CMSHeap`: uses a different approach to solve the same problem
///
/// # References
/// - ["Approximate Frequency Counts over Data Streams", Gurmeet S. Manku, Rajeev Motwani, 2002](https://www.vldb.org/conf/2002/S10P03.pdf)
/// - [Wikipedia: Lossy Count Algorithm](https://en.wikipedia.org/wiki/Lossy_Count_Algorithm)
/// - ["Top K Frequent Items Algorithm", Zhipeng Jiang, 2017](https://zpjiang.me/2017/11/13/top-k-elementes-system-design/)
#[derive(Clone, Debug)]
pub struct LossyCounter<T>
where
    T: Clone + Eq + Hash,
{
    epsilon: f64,
    known: HashMap<T, KnownEntry>,
    n: usize,
    width: usize,
}

impl<T> LossyCounter<T>
where
    T: Clone + Eq + Hash,
{
    /// Creates new lossy counter so that for reported frequencies `f_e` it holds:
    ///
    /// ```text
    /// f <= f_e <= epsilon * n
    /// ```
    ///
    /// where `f` is the true frequency and `n` the number of data points seen so far.
    pub fn with_properties(epsilon: f64) -> Self {
        assert!(
            (epsilon > 0.) & (epsilon < 1.),
            "epsilon ({}) must be greater than 0 and smaller than 1",
            epsilon
        );

        Self {
            epsilon,
            known: HashMap::new(),
            n: 0,
            width: (1. / epsilon).ceil() as usize,
        }
    }

    /// Epsilon error.
    pub fn epsilon(&self) -> f64 {
        self.epsilon
    }

    /// Number of data points seen so far.
    pub fn n(&self) -> usize {
        self.n
    }

    /// Add new element to the counter.
    ///
    /// Reports, if the element was considered new (`true`) or not (`false`).
    pub fn add(&mut self, t: T) -> bool {
        // pre-inc, since "N denotes the current length of the stream"
        self.n += 1;

        let at_window_end = self.n % self.width == 0;
        let b_current = self.n / self.width + if at_window_end { 0 } else { 1 };

        // add new data
        let was_new = match self.known.entry(t) {
            Entry::Occupied(mut o) => {
                let mut value = o.get_mut();
                value.f += 1;
                false
            }
            Entry::Vacant(v) => {
                v.insert(KnownEntry {
                    f: 1,
                    delta: b_current - 1,
                });
                true
            }
        };

        // pruning
        if at_window_end {
            self.known = self
                .known
                .drain()
                .filter(|(_k, v)| v.f + v.delta > b_current)
                .collect();
        }

        was_new
    }

    /// Query elements for which, with their guessed frequency `f`, it holds:
    ///
    /// ```text
    /// f >= (threshold - epsilon) * n
    /// f > epsilon * n
    /// ```
    ///
    /// The order of the elements is undefined.
    pub fn query<'a>(&'a self, threshold: f64) -> impl 'a + Iterator<Item = T> {
        let bound = (((threshold - self.epsilon) * (self.n as f64)).ceil()).max(0.) as usize;
        self.known
            .iter()
            .filter(move |(_k, v)| v.f >= bound)
            .map(|(k, _v)| k)
            .cloned()
    }
}

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

    #[test]
    fn new() {
        let counter = LossyCounter::<u64>::with_properties(0.5);
        assert_eq!(counter.epsilon(), 0.5);
        assert_eq!(counter.n(), 0);
    }

    #[test]
    #[should_panic(expected = "epsilon (0) must be greater than 0 and smaller than 1")]
    fn new_panics_epsilon_0() {
        LossyCounter::<u64>::with_properties(0.);
    }

    #[test]
    #[should_panic(expected = "epsilon (1) must be greater than 0 and smaller than 1")]
    fn new_panics_epsilon_1() {
        LossyCounter::<u64>::with_properties(1.);
    }

    #[test]
    fn add() {
        let mut counter = LossyCounter::<u64>::with_properties(0.5);
        assert!(counter.add(13));
        assert_eq!(counter.n(), 1);
    }

    #[test]
    fn double_add() {
        let mut counter = LossyCounter::<u64>::with_properties(0.5);
        assert!(counter.add(13));
        assert!(!counter.add(13));
        assert_eq!(counter.n(), 2);
    }

    #[test]
    fn query_all() {
        let mut counter = LossyCounter::<u64>::with_properties(0.2);
        assert!(counter.add(13));
        assert!(counter.add(42));

        let mut data: Vec<u64> = counter.query(0.).collect();
        data.sort();
        assert_eq!(data, vec![13, 42]);
    }

    #[test]
    fn query_part() {
        let mut counter = LossyCounter::<u64>::with_properties(0.001);
        assert!(counter.add(13));
        assert!(!counter.add(13));
        assert!(counter.add(42));

        let mut data: Vec<u64> = counter.query(0.6).collect();
        data.sort();
        assert_eq!(data, vec![13]);
    }

    #[test]
    fn query_large() {
        let mut counter = LossyCounter::<u64>::with_properties(0.01);
        for i in 0..1000 {
            let j = i % 10;
            if j <= 6 {
                counter.add(i);
            } else {
                counter.add(j);
            }
        }

        let mut data: Vec<u64> = counter.query(0.02).collect();
        data.sort();
        assert_eq!(data, vec![7, 8, 9]);
    }

    #[test]
    fn clone() {
        let mut counter1 = LossyCounter::<u64>::with_properties(0.2);
        assert!(counter1.add(13));

        let mut counter2 = counter1.clone();
        assert!(counter2.add(42));

        assert_eq!(counter1.n(), 1);
        assert_eq!(counter2.n(), 2);

        let mut data1: Vec<u64> = counter1.query(0.).collect();
        data1.sort();
        assert_eq!(data1, vec![13]);

        let mut data2: Vec<u64> = counter2.query(0.).collect();
        data2.sort();
        assert_eq!(data2, vec![13, 42]);
    }
}
<commit_msg>lossycounter: impl clear<commit_after>//! LossyCounter implementation.

use std::collections::hash_map::{Entry, HashMap};
use std::hash::Hash;

#[derive(Clone, Debug)]
struct KnownEntry {
    f: usize,
    delta: usize,
}

/// A LossyCounter is a data structure that memorizes the most frequent elements in data stream.
///
/// # Examples
/// ```
/// use pdatastructs::topk::lossycounter::LossyCounter;
///
/// // set up filter
/// let epsilon = 0.01;  // error threshold
/// let mut lc = LossyCounter::with_properties(epsilon);
///
/// // add some data
/// for i in 0..1000 {
///     let x = i % 10;
///     let y = if x < 4 {
///         0
///     } else if x < 7 {
///         1
///     } else {
///         x
///     };
///     lc.add(y);
/// }
///
/// // later
/// let threshold = 0.2;
/// let mut elements: Vec<u64> = lc.query(threshold).collect();
/// elements.sort();  // normalize order for testing purposes
/// assert_eq!(elements, vec![0, 1]);
/// ```
///
/// # Applications
/// - getting a fixed number of most common example of a large data set
/// - detect hotspots / very common events
///
/// # How It Works
/// The LossyCounter is initialized with an relative error bound `epsilon`. Depending on that, a
/// window size will be set. A window is the number of elements after which the counter will be
/// pruned.
///
/// ## Insertion
/// If the element is unknown (i.e. it was never seen before or was already pruned), it will be
/// stored with a frequency of 1. Also, the current window index will be stored alongside.
///
/// ```text
/// window size    = 4
///
///
/// insert(a):
///              n = 1
/// current window = 1
///
/// +---------+-------+-----------+
/// | element | delta | frequency |
/// +=========+=======+===========+
/// |       a |     0 |         1 |  <-- inserted
/// +---------+-------+-----------+
///
///
/// insert(b):
///              n = 2
/// current window = 1
///
/// +---------+-------+-----------+
/// | element | delta | frequency |
/// +=========+=======+===========+
/// |       a |     0 |         1 |
/// |       b |     0 |         1 |  <-- inserted
/// +---------+-------+-----------+
/// ```
///
/// If the element is know, the counter will be increased by 1.
///
/// ```text
/// window size    = 4
///
///
/// insert(a):
///              n = 3
/// current window = 1
///
/// +---------+-------+-----------+
/// | element | delta | frequency |
/// +=========+=======+===========+
/// |       a |     0 |         2 |  <-- incremented
/// |       b |     0 |         1 |
/// +---------+-------+-----------+
///
///
/// insert(a):
///              n = 4
/// current window = 1
///
/// +---------+-------+-----------+
/// | element | delta | frequency |
/// +=========+=======+===========+
/// |       a |     0 |         3 |  <-- incremented
/// |       b |     0 |         1 |
/// +---------+-------+-----------+
/// ```
///
/// If the window ends, pruning takes place. Elements will only be kept if their recorded frequency
/// plus the window index stored with them (i.e. the index they where recorded first) is at least
/// as large as the current window index. So elements that where not seen for a while will slowly
/// be kicked out of the counter, hence the name "Lossy Counter". In other words: an element will
/// only stay in the counter if it was seen more often than the number of windows since it was
/// inserted (i.e. number of windows plus 1).
///
/// ```text
/// window size    = 4
///
///
/// prune:
///              n = 4
/// current window = 1
///
/// +---------+-------+-----------+
/// | element | delta | frequency |
/// +=========+=======+===========+
/// |       a |     0 |         2 |
/// |       b |     0 |         1 |  <-- remove
/// +---------+-------+-----------+
///
/// +---------+-------+-----------+
/// | element | delta | frequency |
/// +=========+=======+===========+
/// |       a |     0 |         2 |
/// +---------+-------+-----------+
/// ```
///
/// ## Query
/// Given a relative threshold, all elements will be returned for which the following holds:
///
/// ```text
/// f >= (threshold - epsilon) * n
/// ```
///
/// # See Also
/// - `std::collections::HashSet`: has a false positive rate of 0%, but also needs to store all
///   elements
/// - `pdatastructs::topk::cmsheap::CMSHeap`: uses a different approach to solve the same problem
///
/// # References
/// - ["Approximate Frequency Counts over Data Streams", Gurmeet S. Manku, Rajeev Motwani, 2002](https://www.vldb.org/conf/2002/S10P03.pdf)
/// - [Wikipedia: Lossy Count Algorithm](https://en.wikipedia.org/wiki/Lossy_Count_Algorithm)
/// - ["Top K Frequent Items Algorithm", Zhipeng Jiang, 2017](https://zpjiang.me/2017/11/13/top-k-elementes-system-design/)
#[derive(Clone, Debug)]
pub struct LossyCounter<T>
where
    T: Clone + Eq + Hash,
{
    epsilon: f64,
    known: HashMap<T, KnownEntry>,
    n: usize,
    width: usize,
}

impl<T> LossyCounter<T>
where
    T: Clone + Eq + Hash,
{
    /// Creates new lossy counter so that for reported frequencies `f_e` it holds:
    ///
    /// ```text
    /// f <= f_e <= epsilon * n
    /// ```
    ///
    /// where `f` is the true frequency and `n` the number of data points seen so far.
    pub fn with_properties(epsilon: f64) -> Self {
        assert!(
            (epsilon > 0.) & (epsilon < 1.),
            "epsilon ({}) must be greater than 0 and smaller than 1",
            epsilon
        );

        Self {
            epsilon,
            known: HashMap::new(),
            n: 0,
            width: (1. / epsilon).ceil() as usize,
        }
    }

    /// Epsilon error.
    pub fn epsilon(&self) -> f64 {
        self.epsilon
    }

    /// Number of data points seen so far.
    pub fn n(&self) -> usize {
        self.n
    }

    /// Add new element to the counter.
    ///
    /// Reports, if the element was considered new (`true`) or not (`false`).
    pub fn add(&mut self, t: T) -> bool {
        // pre-inc, since "N denotes the current length of the stream"
        self.n += 1;

        let at_window_end = self.n % self.width == 0;
        let b_current = self.n / self.width + if at_window_end { 0 } else { 1 };

        // add new data
        let was_new = match self.known.entry(t) {
            Entry::Occupied(mut o) => {
                let mut value = o.get_mut();
                value.f += 1;
                false
            }
            Entry::Vacant(v) => {
                v.insert(KnownEntry {
                    f: 1,
                    delta: b_current - 1,
                });
                true
            }
        };

        // pruning
        if at_window_end {
            self.known = self
                .known
                .drain()
                .filter(|(_k, v)| v.f + v.delta > b_current)
                .collect();
        }

        was_new
    }

    /// Query elements for which, with their guessed frequency `f`, it holds:
    ///
    /// ```text
    /// f >= (threshold - epsilon) * n
    /// f > epsilon * n
    /// ```
    ///
    /// The order of the elements is undefined.
    pub fn query<'a>(&'a self, threshold: f64) -> impl 'a + Iterator<Item = T> {
        let bound = (((threshold - self.epsilon) * (self.n as f64)).ceil()).max(0.) as usize;
        self.known
            .iter()
            .filter(move |(_k, v)| v.f >= bound)
            .map(|(k, _v)| k)
            .cloned()
    }

    /// Clear state of the counter.
    pub fn clear(&mut self) {
        self.known = HashMap::new();
        self.n = 0;
    }
}

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

    #[test]
    fn new() {
        let counter = LossyCounter::<u64>::with_properties(0.5);
        assert_eq!(counter.epsilon(), 0.5);
        assert_eq!(counter.n(), 0);
    }

    #[test]
    #[should_panic(expected = "epsilon (0) must be greater than 0 and smaller than 1")]
    fn new_panics_epsilon_0() {
        LossyCounter::<u64>::with_properties(0.);
    }

    #[test]
    #[should_panic(expected = "epsilon (1) must be greater than 0 and smaller than 1")]
    fn new_panics_epsilon_1() {
        LossyCounter::<u64>::with_properties(1.);
    }

    #[test]
    fn add() {
        let mut counter = LossyCounter::<u64>::with_properties(0.5);
        assert!(counter.add(13));
        assert_eq!(counter.n(), 1);
    }

    #[test]
    fn double_add() {
        let mut counter = LossyCounter::<u64>::with_properties(0.5);
        assert!(counter.add(13));
        assert!(!counter.add(13));
        assert_eq!(counter.n(), 2);
    }

    #[test]
    fn query_all() {
        let mut counter = LossyCounter::<u64>::with_properties(0.2);
        assert!(counter.add(13));
        assert!(counter.add(42));

        let mut data: Vec<u64> = counter.query(0.).collect();
        data.sort();
        assert_eq!(data, vec![13, 42]);
    }

    #[test]
    fn query_part() {
        let mut counter = LossyCounter::<u64>::with_properties(0.001);
        assert!(counter.add(13));
        assert!(!counter.add(13));
        assert!(counter.add(42));

        let mut data: Vec<u64> = counter.query(0.6).collect();
        data.sort();
        assert_eq!(data, vec![13]);
    }

    #[test]
    fn query_large() {
        let mut counter = LossyCounter::<u64>::with_properties(0.01);
        for i in 0..1000 {
            let j = i % 10;
            if j <= 6 {
                counter.add(i);
            } else {
                counter.add(j);
            }
        }

        let mut data: Vec<u64> = counter.query(0.02).collect();
        data.sort();
        assert_eq!(data, vec![7, 8, 9]);
    }

    #[test]
    fn clone() {
        let mut counter1 = LossyCounter::<u64>::with_properties(0.2);
        assert!(counter1.add(13));

        let mut counter2 = counter1.clone();
        assert!(counter2.add(42));

        assert_eq!(counter1.n(), 1);
        assert_eq!(counter2.n(), 2);

        let mut data1: Vec<u64> = counter1.query(0.).collect();
        data1.sort();
        assert_eq!(data1, vec![13]);

        let mut data2: Vec<u64> = counter2.query(0.).collect();
        data2.sort();
        assert_eq!(data2, vec![13, 42]);
    }

    #[test]
    fn clear() {
        let mut counter = LossyCounter::<u64>::with_properties(0.2);
        assert!(counter.add(13));
        assert_eq!(counter.n(), 1);

        counter.clear();
        assert_eq!(counter.n(), 0);
        let data: Vec<u64> = counter.query(0.).collect();
        assert!(data.is_empty());

        assert!(counter.add(13));
        assert_eq!(counter.n(), 1);
        let data: Vec<u64> = counter.query(0.).collect();
        assert_eq!(data, vec![13]);
    }
}
<|endoftext|>


<commit_before>extern crate vastatrix;
extern crate futures;
extern crate env_logger;
use futures::{Future,Async};
use vastatrix::{RamStore,Store};
use vastatrix::LogPos;
use vastatrix::{Error,ErrorKind};

#[test]
fn can_append_one() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();
    store.append_entry(current, next, b"foobar".to_vec()).wait().expect("append_entry");
    let (off, val) = store.fetch_next(current).wait().expect("fetch");

    assert_eq!((off, val), (next, b"foobar".to_vec()))
}

#[test]
fn fetching_one_is_lazy() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();
    let mut fetch_f = store.fetch_next(current);
    assert_eq!(fetch_f.poll().expect("poll-notready"), Async::NotReady);

    store.append_entry(current, next, b"foobar".to_vec()).wait().expect("append_entry");

    let (off, val) = fetch_f.wait().expect("fetch");
    assert_eq!((off, val), (next, b"foobar".to_vec()))
}

#[test]
fn writes_are_lazy() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();

    let store_f = store.append_entry(current, next, b"foobar".to_vec());
    let mut fetch_f = store.fetch_next(current);
    assert_eq!(fetch_f.poll().expect("poll-notready"), Async::NotReady);

    store_f.wait().expect("append_entry");

    let (off, val) = fetch_f.wait().expect("fetch");
    assert_eq!((off, val), (next, b"foobar".to_vec()))
}

#[test]
fn can_write_many() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();
    store.append_entry(current, next, b"foo".to_vec()).wait().expect("append_entry 1");
    let current = next; let next = next.next();
    store.append_entry(current, next, b"bar".to_vec()).wait().expect("append_entry 2");

    let fetch_f = store.fetch_next(LogPos::zero())
                  .and_then(|(curr, first)| {
                          store.fetch_next(curr).map(|(_, second)| vec![first, second])
                          });
    let res = fetch_f.wait().expect("fetch");
    assert_eq!(res, vec![b"foo", b"bar"])
}

#[test]
fn cannot_overwrite_item() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();

    store.append_entry(current, next, b"foo".to_vec()).wait().expect("append_entry 1");
    let overwrite_res = store.append_entry(current, next, b"bar".to_vec()).wait();

    let expected_seq = head_from_error(overwrite_res.unwrap_err());
    assert_eq!(expected_seq, Some(next));
}

#[test]
fn cannot_overwrite_history() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();

    store.append_entry(current, next, b"foo".to_vec()).wait().expect("append_entry 1");
    let current = next; let next = next.next();
    store.append_entry(current, next, b"bar".to_vec()).wait().expect("append_entry 1");
    let overwrite_res = store.append_entry(LogPos::zero(), LogPos::zero().next(), b"moo".to_vec()).wait();

    let expected_seq = head_from_error(overwrite_res.unwrap_err());
    assert_eq!(expected_seq, Some(next));
}

#[test]
fn error_feedback_should_indicate_new_head() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();

    store.append_entry(current, next, b"foo".to_vec()).wait().expect("append_entry 1");
    let overwrite_res = store.append_entry(LogPos::zero(), LogPos::zero().next(), b"moo".to_vec()).wait();

    let new_head = head_from_error(overwrite_res.unwrap_err()).expect("current sequence number");

    let final_write = store.append_entry(new_head, new_head.next(), b"moo".to_vec()).wait();
    assert!(final_write.is_ok());
}

#[test]
fn concurrent_writes_should_be_able_to_recover() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();

    // Request a write from a slow client
    let write_1 = store.append_entry(current, next, b"foo".to_vec());
    // A second client gets their first
    store.append_entry(current, next, b"foo".to_vec()).wait().expect("append_entry 1");

    // Wait for the first write to be completed
    let overwrite_res = write_1.wait();

    // Retry the first write
    let new_head = head_from_error(overwrite_res.unwrap_err()).expect("current sequence number");
    let final_write = store.append_entry(new_head, new_head.next(), b"foo".to_vec()).wait();
    assert!(final_write.is_ok());
}

fn head_from_error(error: Error) -> Option<LogPos> {
    if let &ErrorKind::BadSequence(n) = error.kind() {
        Some(n)
    } else {
        None
    }
}
<commit_msg>Spelling.<commit_after>extern crate vastatrix;
extern crate futures;
extern crate env_logger;
use futures::{Future,Async};
use vastatrix::{RamStore,Store};
use vastatrix::LogPos;
use vastatrix::{Error,ErrorKind};

#[test]
fn can_append_one() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();
    store.append_entry(current, next, b"foobar".to_vec()).wait().expect("append_entry");
    let (off, val) = store.fetch_next(current).wait().expect("fetch");

    assert_eq!((off, val), (next, b"foobar".to_vec()))
}

#[test]
fn fetching_one_is_lazy() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();
    let mut fetch_f = store.fetch_next(current);
    assert_eq!(fetch_f.poll().expect("poll-notready"), Async::NotReady);

    store.append_entry(current, next, b"foobar".to_vec()).wait().expect("append_entry");

    let (off, val) = fetch_f.wait().expect("fetch");
    assert_eq!((off, val), (next, b"foobar".to_vec()))
}

#[test]
fn writes_are_lazy() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();

    let store_f = store.append_entry(current, next, b"foobar".to_vec());
    let mut fetch_f = store.fetch_next(current);
    assert_eq!(fetch_f.poll().expect("poll-notready"), Async::NotReady);

    store_f.wait().expect("append_entry");

    let (off, val) = fetch_f.wait().expect("fetch");
    assert_eq!((off, val), (next, b"foobar".to_vec()))
}

#[test]
fn can_write_many() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();
    store.append_entry(current, next, b"foo".to_vec()).wait().expect("append_entry 1");
    let current = next; let next = next.next();
    store.append_entry(current, next, b"bar".to_vec()).wait().expect("append_entry 2");

    let fetch_f = store.fetch_next(LogPos::zero())
                  .and_then(|(curr, first)| {
                          store.fetch_next(curr).map(|(_, second)| vec![first, second])
                          });
    let res = fetch_f.wait().expect("fetch");
    assert_eq!(res, vec![b"foo", b"bar"])
}

#[test]
fn cannot_overwrite_item() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();

    store.append_entry(current, next, b"foo".to_vec()).wait().expect("append_entry 1");
    let overwrite_res = store.append_entry(current, next, b"bar".to_vec()).wait();

    let expected_seq = head_from_error(overwrite_res.unwrap_err());
    assert_eq!(expected_seq, Some(next));
}

#[test]
fn cannot_overwrite_history() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();

    store.append_entry(current, next, b"foo".to_vec()).wait().expect("append_entry 1");
    let current = next; let next = next.next();
    store.append_entry(current, next, b"bar".to_vec()).wait().expect("append_entry 1");
    let overwrite_res = store.append_entry(LogPos::zero(), LogPos::zero().next(), b"moo".to_vec()).wait();

    let expected_seq = head_from_error(overwrite_res.unwrap_err());
    assert_eq!(expected_seq, Some(next));
}

#[test]
fn error_feedback_should_indicate_new_head() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();

    store.append_entry(current, next, b"foo".to_vec()).wait().expect("append_entry 1");
    let overwrite_res = store.append_entry(LogPos::zero(), LogPos::zero().next(), b"moo".to_vec()).wait();

    let new_head = head_from_error(overwrite_res.unwrap_err()).expect("current sequence number");

    let final_write = store.append_entry(new_head, new_head.next(), b"moo".to_vec()).wait();
    assert!(final_write.is_ok());
}

#[test]
fn concurrent_writes_should_be_able_to_recover() {
    env_logger::init().unwrap_or(());
    let store = RamStore::new();
    let current = LogPos::zero();
    let next = current.next();

    // Request a write from a slow client
    let write_1 = store.append_entry(current, next, b"foo".to_vec());
    // A second client gets there first
    store.append_entry(current, next, b"foo".to_vec()).wait().expect("append_entry 1");

    // Wait for the first write to be completed
    let overwrite_res = write_1.wait();

    // Retry the first write
    let new_head = head_from_error(overwrite_res.unwrap_err()).expect("current sequence number");
    let final_write = store.append_entry(new_head, new_head.next(), b"foo".to_vec()).wait();
    assert!(final_write.is_ok());
}

fn head_from_error(error: Error) -> Option<LogPos> {
    if let &ErrorKind::BadSequence(n) = error.kind() {
        Some(n)
    } else {
        None
    }
}
<|endoftext|>