use std::collections::{BTreeMap, HashMap};
use super::functions::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ArenaMove {
pub id: usize,
pub polarity: Polarity,
pub initial: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FinitePartialOrder {
pub n: usize,
pub leq: Vec<Vec<bool>>,
}
impl FinitePartialOrder {
pub fn discrete(n: usize) -> Self {
let leq = (0..n).map(|i| (0..n).map(|j| i == j).collect()).collect();
FinitePartialOrder { n, leq }
}
pub fn flat(n: usize) -> Self {
let k = n + 1;
let leq = (0..k)
.map(|i| (0..k).map(|j| i == j || i == 0).collect())
.collect();
FinitePartialOrder { n: k, leq }
}
pub fn is_reflexive(&self) -> bool {
(0..self.n).all(|i| self.leq[i][i])
}
pub fn is_transitive(&self) -> bool {
for i in 0..self.n {
for j in 0..self.n {
for k in 0..self.n {
if self.leq[i][j] && self.leq[j][k] && !self.leq[i][k] {
return false;
}
}
}
}
true
}
pub fn is_antisymmetric(&self) -> bool {
for i in 0..self.n {
for j in 0..self.n {
if i != j && self.leq[i][j] && self.leq[j][i] {
return false;
}
}
}
true
}
pub fn is_valid(&self) -> bool {
self.is_reflexive() && self.is_transitive() && self.is_antisymmetric()
}
pub fn lub(&self, a: usize, b: usize) -> Option<usize> {
let ubs: Vec<usize> = (0..self.n)
.filter(|&x| self.leq[a][x] && self.leq[b][x])
.collect();
ubs.iter()
.find(|&&x| ubs.iter().all(|&y| self.leq[x][y]))
.copied()
}
pub fn glb(&self, a: usize, b: usize) -> Option<usize> {
let lbs: Vec<usize> = (0..self.n)
.filter(|&x| self.leq[x][a] && self.leq[x][b])
.collect();
lbs.iter()
.find(|&&x| lbs.iter().all(|&y| self.leq[y][x]))
.copied()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Trace<A: Clone + Eq> {
pub actions: Vec<A>,
}
impl<A: Clone + Eq> Trace<A> {
pub fn empty() -> Self {
Trace { actions: vec![] }
}
pub fn new(actions: Vec<A>) -> Self {
Trace { actions }
}
pub fn extend(&self, a: A) -> Self {
let mut acts = self.actions.clone();
acts.push(a);
Trace { actions: acts }
}
pub fn concat(&self, other: &Self) -> Self {
let mut acts = self.actions.clone();
acts.extend_from_slice(&other.actions);
Trace { actions: acts }
}
pub fn is_prefix_of(&self, other: &Self) -> bool {
other.actions.starts_with(&self.actions)
}
pub fn len(&self) -> usize {
self.actions.len()
}
pub fn is_empty(&self) -> bool {
self.actions.is_empty()
}
}
#[derive(Debug, Clone)]
pub struct KleenePCA {
pub combinators: HashMap<String, usize>,
pub apply_table: HashMap<(usize, usize), usize>,
next_idx: usize,
}
impl KleenePCA {
pub fn with_ks() -> Self {
let mut pca = KleenePCA {
combinators: HashMap::new(),
apply_table: HashMap::new(),
next_idx: 6,
};
pca.combinators.insert("K".to_string(), 0);
pca.combinators.insert("S".to_string(), 1);
pca.combinators.insert("I".to_string(), 2);
for a in 0usize..3 {
let ka = 3 + a;
pca.apply_table.insert((0, a), ka);
for b in 0usize..3 {
pca.apply_table.insert((ka, b), a);
}
}
for a in 0usize..3 {
pca.apply_table.insert((2, a), a);
}
pca
}
pub fn lookup(&self, name: &str) -> Option<usize> {
self.combinators.get(name).copied()
}
pub fn apply(&self, f: usize, x: usize) -> Option<usize> {
self.apply_table.get(&(f, x)).copied()
}
pub fn add_element(&mut self, name: impl Into<String>) -> usize {
let idx = self.next_idx;
self.combinators.insert(name.into(), idx);
self.next_idx += 1;
idx
}
pub fn define_app(&mut self, f: usize, x: usize, result: usize) {
self.apply_table.insert((f, x), result);
}
pub fn check_k_law(&self) -> bool {
let k = match self.lookup("K") {
Some(v) => v,
None => return false,
};
for a in 0usize..3 {
let ka = match self.apply(k, a) {
Some(v) => v,
None => return false,
};
for b in 0usize..3 {
match self.apply(ka, b) {
Some(r) if r == a => {}
_ => return false,
}
}
}
true
}
pub fn check_i_law(&self) -> bool {
let i = match self.lookup("I") {
Some(v) => v,
None => return false,
};
(0..3).all(|a| self.apply(i, a) == Some(a))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Polarity {
O,
P,
}
#[derive(Debug, Clone)]
pub struct BilimitApprox {
pub levels: Vec<BilimitStep>,
}
impl BilimitApprox {
pub fn new(levels: Vec<BilimitStep>) -> Self {
BilimitApprox { levels }
}
pub fn depth(&self) -> usize {
self.levels.len()
}
pub fn project_to_base(&self, mut x: usize, l: usize) -> usize {
for step in self.levels.iter().take(l).rev() {
x = step.project(x);
}
x
}
}
#[derive(Debug, Clone)]
pub struct LogicalRelation {
pub pairs: HashMap<String, Vec<(usize, usize)>>,
}
impl LogicalRelation {
pub fn new() -> Self {
LogicalRelation {
pairs: HashMap::new(),
}
}
pub fn add(&mut self, ty_code: impl Into<String>, a: usize, b: usize) {
self.pairs.entry(ty_code.into()).or_default().push((a, b));
}
pub fn relates(&self, ty_code: &str, a: usize, b: usize) -> bool {
self.pairs
.get(ty_code)
.map_or(false, |v| v.contains(&(a, b)))
}
pub fn is_reflexive_on(&self, ty_code: &str, domain_size: usize) -> bool {
(0..domain_size).all(|a| self.relates(ty_code, a, a))
}
pub fn is_symmetric_on(&self, ty_code: &str) -> bool {
if let Some(pairs) = self.pairs.get(ty_code) {
pairs.iter().all(|&(a, b)| pairs.contains(&(b, a)))
} else {
true
}
}
pub fn size(&self, ty_code: &str) -> usize {
self.pairs.get(ty_code).map_or(0, |v| v.len())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LambdaTerm {
Var(usize),
Lam(Box<LambdaTerm>),
App(Box<LambdaTerm>, Box<LambdaTerm>),
Const(String),
}
impl LambdaTerm {
pub fn var(n: usize) -> Self {
LambdaTerm::Var(n)
}
pub fn lam(body: LambdaTerm) -> Self {
LambdaTerm::Lam(Box::new(body))
}
pub fn app(f: LambdaTerm, x: LambdaTerm) -> Self {
LambdaTerm::App(Box::new(f), Box::new(x))
}
pub fn cst(s: impl Into<String>) -> Self {
LambdaTerm::Const(s.into())
}
pub fn size(&self) -> usize {
match self {
LambdaTerm::Var(_) | LambdaTerm::Const(_) => 1,
LambdaTerm::Lam(b) => 1 + b.size(),
LambdaTerm::App(f, x) => 1 + f.size() + x.size(),
}
}
pub fn has_free_var(&self, depth: usize, target: usize) -> bool {
match self {
LambdaTerm::Var(n) => *n == target + depth,
LambdaTerm::Const(_) => false,
LambdaTerm::Lam(b) => b.has_free_var(depth + 1, target),
LambdaTerm::App(f, x) => f.has_free_var(depth, target) || x.has_free_var(depth, target),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MaybeInterp {
pub fuel: u64,
}
impl MaybeInterp {
pub fn new(fuel: u64) -> Self {
MaybeInterp { fuel }
}
pub fn ret(v: PCFValue) -> Option<PCFValue> {
Some(v)
}
pub fn bind<F>(m: Option<PCFValue>, f: F) -> Option<PCFValue>
where
F: FnOnce(PCFValue) -> Option<PCFValue>,
{
m.and_then(f)
}
pub fn eval(&self, term: &PCFTerm) -> Option<PCFValue> {
let v = pcf_eval(term, self.fuel);
if v.is_bottom() {
None
} else {
Some(v)
}
}
pub fn guard(cond: bool) -> Option<()> {
if cond {
Some(())
} else {
None
}
}
pub fn seq(&self, t1: &PCFTerm, t2: &PCFTerm) -> Option<PCFValue> {
Self::bind(self.eval(t1), |_| self.eval(t2))
}
pub fn map<F>(m: Option<PCFValue>, f: F) -> Option<PCFValue>
where
F: FnOnce(PCFValue) -> PCFValue,
{
m.map(f)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScottOpen {
pub domain_size: usize,
pub elements: Vec<usize>,
}
impl ScottOpen {
pub fn new(domain_size: usize, elems: impl IntoIterator<Item = usize>) -> Self {
let mut v: Vec<usize> = elems
.into_iter()
.filter(|&x| x > 0 && x < domain_size)
.collect();
v.sort_unstable();
v.dedup();
ScottOpen {
domain_size,
elements: v,
}
}
pub fn top(domain_size: usize) -> Self {
ScottOpen {
domain_size,
elements: (1..domain_size).collect(),
}
}
pub fn empty(domain_size: usize) -> Self {
ScottOpen {
domain_size,
elements: vec![],
}
}
pub fn contains(&self, x: usize) -> bool {
self.elements.binary_search(&x).is_ok()
}
pub fn union(&self, other: &Self) -> Self {
let mut v = self.elements.clone();
for &x in &other.elements {
if !self.contains(x) {
v.push(x);
}
}
v.sort_unstable();
ScottOpen {
domain_size: self.domain_size,
elements: v,
}
}
pub fn intersection(&self, other: &Self) -> Self {
let v: Vec<usize> = self
.elements
.iter()
.filter(|&&x| other.contains(x))
.copied()
.collect();
ScottOpen {
domain_size: self.domain_size,
elements: v,
}
}
pub fn is_scott_open(&self) -> bool {
!self.contains(0)
}
pub fn characteristic(&self, x: usize) -> bool {
self.contains(x)
}
}
#[derive(Debug, Clone)]
pub struct GameArena {
pub moves: Vec<ArenaMove>,
pub enables: HashMap<usize, Vec<usize>>,
}
impl GameArena {
pub fn new(moves: Vec<ArenaMove>) -> Self {
GameArena {
moves,
enables: HashMap::new(),
}
}
pub fn add_enables(&mut self, from: usize, to: usize) {
self.enables.entry(from).or_default().push(to);
}
pub fn initial_moves(&self) -> Vec<&ArenaMove> {
self.moves.iter().filter(|m| m.initial).collect()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PCFValue {
Num(u64),
Bool(bool),
Bottom,
Closure(Box<PCFTerm>, usize),
}
impl PCFValue {
pub fn is_bottom(&self) -> bool {
matches!(self, PCFValue::Bottom)
}
pub fn is_nat(&self) -> bool {
matches!(self, PCFValue::Num(_))
}
}
#[derive(Clone)]
pub struct MonotoneMap {
pub table: Vec<usize>,
}
impl MonotoneMap {
pub fn new(table: Vec<usize>) -> Self {
MonotoneMap { table }
}
pub fn apply(&self, x: usize) -> usize {
self.table[x]
}
pub fn is_monotone(&self, po: &FinitePartialOrder) -> bool {
for i in 0..po.n.min(self.table.len()) {
for j in 0..po.n.min(self.table.len()) {
if po.leq[i][j] {
let fi = self.table[i];
let fj = self.table[j];
if fi < po.n && fj < po.n && !po.leq[fi][fj] {
return false;
}
}
}
}
true
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PCFTerm {
Var(usize),
Zero,
True,
False,
Succ(Box<PCFTerm>),
Pred(Box<PCFTerm>),
IsZero(Box<PCFTerm>),
Lam(Box<PCFTerm>),
App(Box<PCFTerm>, Box<PCFTerm>),
Fix(Box<PCFTerm>),
If(Box<PCFTerm>, Box<PCFTerm>, Box<PCFTerm>),
}
impl PCFTerm {
pub fn label(&self) -> &'static str {
match self {
PCFTerm::Var(_) => "Var",
PCFTerm::Zero => "Zero",
PCFTerm::True => "True",
PCFTerm::False => "False",
PCFTerm::Succ(_) => "Succ",
PCFTerm::Pred(_) => "Pred",
PCFTerm::IsZero(_) => "IsZero",
PCFTerm::Lam(_) => "Lam",
PCFTerm::App(_, _) => "App",
PCFTerm::Fix(_) => "Fix",
PCFTerm::If(_, _, _) => "If",
}
}
}
#[derive(Debug, Clone)]
pub struct BilimitStep {
pub size: usize,
pub proj: Vec<usize>,
}
impl BilimitStep {
pub fn new(size: usize, proj: Vec<usize>) -> Self {
BilimitStep { size, proj }
}
pub fn project(&self, x: usize) -> usize {
self.proj.get(x).copied().unwrap_or(0)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PCFType {
Nat,
Bool,
Arrow(Box<PCFType>, Box<PCFType>),
}
impl PCFType {
pub fn arrow(t1: PCFType, t2: PCFType) -> Self {
PCFType::Arrow(Box::new(t1), Box::new(t2))
}
pub fn name(&self) -> String {
match self {
PCFType::Nat => "Nat".to_string(),
PCFType::Bool => "Bool".to_string(),
PCFType::Arrow(a, b) => format!("({} → {})", a.name(), b.name()),
}
}
}
#[derive(Debug, Clone)]
pub struct FiniteValuation {
pub masses: BTreeMap<String, f64>,
}
impl FiniteValuation {
pub fn empty() -> Self {
FiniteValuation {
masses: BTreeMap::new(),
}
}
pub fn dirac(x: impl Into<String>) -> Self {
let mut m = BTreeMap::new();
m.insert(x.into(), 1.0);
FiniteValuation { masses: m }
}
pub fn total_mass(&self) -> f64 {
self.masses.values().sum()
}
pub fn is_sub_probability(&self) -> bool {
self.total_mass() <= 1.0 + 1e-9
}
pub fn mix(&self, other: &Self, p: f64) -> Self {
let mut m = BTreeMap::new();
for (k, v) in &self.masses {
*m.entry(k.clone()).or_insert(0.0) += (1.0 - p) * v;
}
for (k, v) in &other.masses {
*m.entry(k.clone()).or_insert(0.0) += p * v;
}
FiniteValuation { masses: m }
}
pub fn stochastic_leq(&self, other: &Self) -> bool {
for (k, v) in &self.masses {
let w = other.masses.get(k).copied().unwrap_or(0.0);
if *v > w + 1e-9 {
return false;
}
}
true
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HoareElement {
pub elems: Vec<usize>,
}
impl HoareElement {
pub fn new(iter: impl IntoIterator<Item = usize>) -> Self {
let mut v: Vec<usize> = iter.into_iter().collect();
v.sort_unstable();
v.dedup();
HoareElement { elems: v }
}
pub fn hoare_leq(&self, other: &Self) -> bool {
self.elems.iter().all(|x| other.elems.contains(x))
}
pub fn union(&self, other: &Self) -> Self {
let mut v = self.elems.clone();
for x in &other.elems {
if !v.contains(x) {
v.push(*x);
}
}
v.sort_unstable();
HoareElement { elems: v }
}
}
#[derive(Debug, Clone)]
pub struct InnocentStrategy {
pub responses: HashMap<Vec<usize>, usize>,
}
impl InnocentStrategy {
pub fn new() -> Self {
InnocentStrategy {
responses: HashMap::new(),
}
}
pub fn add_response(&mut self, view: Vec<usize>, p_move: usize) {
self.responses.insert(view, p_move);
}
pub fn respond(&self, view: &[usize]) -> Option<usize> {
self.responses.get(view).copied()
}
pub fn size(&self) -> usize {
self.responses.len()
}
}