diff --git a/hugr-core/src/std_extensions/arithmetic/int_ops.rs b/hugr-core/src/std_extensions/arithmetic/int_ops.rs index 342a887ee..c3785ca9a 100644 --- a/hugr-core/src/std_extensions/arithmetic/int_ops.rs +++ b/hugr-core/src/std_extensions/arithmetic/int_ops.rs @@ -113,60 +113,53 @@ impl MakeOpDef for IntOpDef { fn signature(&self) -> SignatureFunc { use IntOpDef::*; + let tv0 = int_tv(0); match self { iwiden_s | iwiden_u => CustomValidator::new( - int_polytype(2, vec![int_tv(0)], vec![int_tv(1)]), + int_polytype(2, vec![tv0.clone()], vec![int_tv(1)]), IOValidator { f_ge_s: false }, ) .into(), inarrow_s | inarrow_u => CustomValidator::new( - int_polytype(2, int_tv(0), sum_ty_with_err(int_tv(1))), + int_polytype(2, tv0.clone(), sum_ty_with_err(int_tv(1))), IOValidator { f_ge_s: true }, ) .into(), itobool => int_polytype(0, vec![int_type(0)], type_row![BOOL_T]).into(), ifrombool => int_polytype(0, type_row![BOOL_T], vec![int_type(0)]).into(), ieq | ine | ilt_u | ilt_s | igt_u | igt_s | ile_u | ile_s | ige_u | ige_s => { - int_polytype(1, vec![int_tv(0); 2], type_row![BOOL_T]).into() + int_polytype(1, vec![tv0; 2], type_row![BOOL_T]).into() } imax_u | imax_s | imin_u | imin_s | iadd | isub | imul | iand | ior | ixor => { ibinop_sig().into() } ineg | iabs | inot => iunop_sig().into(), - //TODO inline idivmod_checked_u | idivmod_checked_s => { - let intpair: TypeRowRV = vec![int_tv(0), int_tv(1)].into(); + let intpair: TypeRowRV = vec![tv0; 2].into(); int_polytype( - 2, + 1, intpair.clone(), sum_ty_with_err(Type::new_tuple(intpair)), ) } .into(), idivmod_u | idivmod_s => { - let intpair: TypeRowRV = vec![int_tv(0), int_tv(1)].into(); - int_polytype(2, intpair.clone(), intpair.clone()) + let intpair: TypeRowRV = vec![tv0; 2].into(); + int_polytype(1, intpair.clone(), intpair.clone()) } .into(), - idiv_u | idiv_s => int_polytype(2, vec![int_tv(0), int_tv(1)], vec![int_tv(0)]).into(), + idiv_u | idiv_s => int_polytype(1, vec![tv0.clone(); 2], vec![tv0]).into(), idiv_checked_u | idiv_checked_s => { - int_polytype(2, vec![int_tv(0), int_tv(1)], sum_ty_with_err(int_tv(0))).into() + int_polytype(1, vec![tv0.clone(); 2], sum_ty_with_err(tv0)).into() } - imod_checked_u | imod_checked_s => int_polytype( - 2, - vec![int_tv(0), int_tv(1).clone()], - sum_ty_with_err(int_tv(1)), - ) - .into(), - imod_u | imod_s => { - int_polytype(2, vec![int_tv(0), int_tv(1).clone()], vec![int_tv(1)]).into() - } - ishl | ishr | irotl | irotr => { - int_polytype(2, vec![int_tv(0), int_tv(1)], vec![int_tv(0)]).into() + imod_checked_u | imod_checked_s => { + int_polytype(1, vec![tv0.clone(); 2], sum_ty_with_err(tv0)).into() } + imod_u | imod_s => int_polytype(1, vec![tv0.clone(); 2], vec![tv0]).into(), + ishl | ishr | irotl | irotr => int_polytype(1, vec![tv0.clone(); 2], vec![tv0]).into(), itostring_u | itostring_s => PolyFuncTypeRV::new( vec![LOG_WIDTH_TYPE_PARAM], - FuncValueType::new(vec![int_tv(0)], vec![STRING_TYPE]), + FuncValueType::new(vec![tv0], vec![STRING_TYPE]), ) .into(), } @@ -200,13 +193,13 @@ impl MakeOpDef for IntOpDef { isub => "subtraction modulo 2^N (signed and unsigned versions are the same op)", ineg => "negation modulo 2^N (signed and unsigned versions are the same op)", imul => "multiplication modulo 2^N (signed and unsigned versions are the same op)", - idivmod_checked_u => "given unsigned integers 0 <= n < 2^N, 0 <= m < 2^M, generates unsigned q, r where \ + idivmod_checked_u => "given unsigned integers 0 <= n < 2^N, 0 <= m < 2^N, generates unsigned q, r where \ q*m+r=n, 0<=r "given unsigned integers 0 <= n < 2^N, 0 <= m < 2^M, generates unsigned q, r where \ + idivmod_u => "given unsigned integers 0 <= n < 2^N, 0 <= m < 2^N, generates unsigned q, r where \ q*m+r=n, 0<=r "given signed integer -2^{N-1} <= n < 2^{N-1} and unsigned 0 <= m < 2^M, generates \ + idivmod_checked_s => "given signed integer -2^{N-1} <= n < 2^{N-1} and unsigned 0 <= m < 2^N, generates \ signed q and unsigned r where q*m+r=n, 0<=r "given signed integer -2^{N-1} <= n < 2^{N-1} and unsigned 0 <= m < 2^M, generates \ + idivmod_s => "given signed integer -2^{N-1} <= n < 2^{N-1} and unsigned 0 <= m < 2^N, generates \ signed q and unsigned r where q*m+r=n, 0<=r "as idivmod_checked_u but discarding the second output", idiv_u => "as idivmod_u but discarding the second output", diff --git a/hugr-core/src/std_extensions/arithmetic/int_ops/const_fold.rs b/hugr-core/src/std_extensions/arithmetic/int_ops/const_fold.rs index 4c520963d..34725677f 100644 --- a/hugr-core/src/std_extensions/arithmetic/int_ops/const_fold.rs +++ b/hugr-core/src/std_extensions/arithmetic/int_ops/const_fold.rs @@ -590,17 +590,16 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::idivmod_checked_u => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; let (n, m): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; - if n.log_width() != logwidth0 || m.log_width() != logwidth1 { + if n.log_width() != logwidth0 || m.log_width() != logwidth0 { None } else { let q_type = INT_TYPES[logwidth0 as usize].to_owned(); - let r_type = INT_TYPES[logwidth1 as usize].to_owned(); + let r_type = q_type.clone(); let qr_type: Type = Type::new_tuple(vec![q_type, r_type]); let sum_type: SumType = sum_with_error(qr_type); let err_value = || { @@ -620,7 +619,7 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { let rval = nval % mval; Value::tuple(vec![ Value::extension(ConstInt::new_u(logwidth0, qval).unwrap()), - Value::extension(ConstInt::new_u(logwidth1, rval).unwrap()), + Value::extension(ConstInt::new_u(logwidth0, rval).unwrap()), ]) }; Some(vec![(0.into(), out_const)]) @@ -631,21 +630,20 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::idivmod_u => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; let (n, m): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; let nval = n.value_u(); let mval = m.value_u(); - if n.log_width() != logwidth0 || m.log_width() != logwidth1 || mval == 0 { + if n.log_width() != logwidth0 || m.log_width() != logwidth0 || mval == 0 { None } else { let qval = nval / mval; let rval = nval % mval; let q = Value::extension(ConstInt::new_u(logwidth0, qval).unwrap()); - let r = Value::extension(ConstInt::new_u(logwidth1, rval).unwrap()); + let r = Value::extension(ConstInt::new_u(logwidth0, rval).unwrap()); Some(vec![(0.into(), q), (1.into(), r)]) } }, @@ -654,17 +652,17 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::idivmod_checked_s => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n, m): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; - if n.log_width() != logwidth0 || m.log_width() != logwidth1 { + if n.log_width() != logwidth0 || m.log_width() != logwidth0 { None } else { let q_type = INT_TYPES[logwidth0 as usize].to_owned(); - let r_type = INT_TYPES[logwidth1 as usize].to_owned(); + let r_type = INT_TYPES[logwidth0 as usize].to_owned(); let qr_type: Type = Type::new_tuple(vec![q_type, r_type]); let sum_type: SumType = sum_with_error(qr_type); let err_value = || { @@ -683,7 +681,7 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { let (qval, rval) = divmod_s(nval, mval); Value::tuple(vec![ Value::extension(ConstInt::new_s(logwidth0, qval).unwrap()), - Value::extension(ConstInt::new_u(logwidth1, rval).unwrap()), + Value::extension(ConstInt::new_u(logwidth0, rval).unwrap()), ]) }; Some(vec![(0.into(), out_const)]) @@ -694,20 +692,20 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::idivmod_s => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n, m): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; let nval = n.value_s(); let mval = m.value_u(); - if n.log_width() != logwidth0 || m.log_width() != logwidth1 || mval == 0 { + if n.log_width() != logwidth0 || m.log_width() != logwidth0 || mval == 0 { None } else { let (qval, rval) = divmod_s(nval, mval); let q = Value::extension(ConstInt::new_s(logwidth0, qval).unwrap()); - let r = Value::extension(ConstInt::new_u(logwidth1, rval).unwrap()); + let r = Value::extension(ConstInt::new_u(logwidth0, rval).unwrap()); Some(vec![(0.into(), q), (1.into(), r)]) } }, @@ -716,13 +714,13 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::idiv_checked_u => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n, m): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; - if n.log_width() != logwidth0 || m.log_width() != logwidth1 { + if n.log_width() != logwidth0 || m.log_width() != logwidth0 { None } else { let int_out_type = INT_TYPES[logwidth0 as usize].to_owned(); @@ -750,15 +748,15 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::idiv_u => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n, m): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; let nval = n.value_u(); let mval = m.value_u(); - if n.log_width() != logwidth0 || m.log_width() != logwidth1 || mval == 0 { + if n.log_width() != logwidth0 || m.log_width() != logwidth0 || mval == 0 { None } else { let q = Value::extension(ConstInt::new_u(logwidth0, nval / mval).unwrap()); @@ -770,16 +768,16 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::imod_checked_u => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n, m): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; - if n.log_width() != logwidth0 || m.log_width() != logwidth1 { + if n.log_width() != logwidth0 || m.log_width() != logwidth0 { None } else { - let int_out_type = INT_TYPES[logwidth1 as usize].to_owned(); + let int_out_type = INT_TYPES[logwidth0 as usize].to_owned(); let sum_type = sum_with_error(int_out_type.clone()); let err_value = || { let err_val = ConstError { @@ -794,7 +792,7 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { let out_const: Value = if mval == 0 { err_value() } else { - Value::extension(ConstInt::new_u(logwidth1, nval % mval).unwrap()) + Value::extension(ConstInt::new_u(logwidth0, nval % mval).unwrap()) }; Some(vec![(0.into(), out_const)]) } @@ -804,18 +802,18 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::imod_u => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n, m): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; let nval = n.value_u(); let mval = m.value_u(); - if n.log_width() != logwidth0 || m.log_width() != logwidth1 || mval == 0 { + if n.log_width() != logwidth0 || m.log_width() != logwidth0 || mval == 0 { None } else { - let r = Value::extension(ConstInt::new_u(logwidth1, nval % mval).unwrap()); + let r = Value::extension(ConstInt::new_u(logwidth0, nval % mval).unwrap()); Some(vec![(0.into(), r)]) } }, @@ -824,13 +822,13 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::idiv_checked_s => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n, m): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; - if n.log_width() != logwidth0 || m.log_width() != logwidth1 { + if n.log_width() != logwidth0 || m.log_width() != logwidth0 { None } else { let int_out_type = INT_TYPES[logwidth0 as usize].to_owned(); @@ -849,7 +847,7 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { err_value() } else { let (qval, _) = divmod_s(nval, mval); - Value::extension(ConstInt::new_s(logwidth1, qval).unwrap()) + Value::extension(ConstInt::new_s(logwidth0, qval).unwrap()) }; Some(vec![(0.into(), out_const)]) } @@ -859,15 +857,15 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::idiv_s => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n, m): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; let nval = n.value_s(); let mval = m.value_u(); - if n.log_width() != logwidth0 || m.log_width() != logwidth1 || mval == 0 { + if n.log_width() != logwidth0 || m.log_width() != logwidth0 || mval == 0 { None } else { let (qval, _) = divmod_s(nval, mval); @@ -880,16 +878,16 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::imod_checked_s => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n, m): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; - if n.log_width() != logwidth0 || m.log_width() != logwidth1 { + if n.log_width() != logwidth0 || m.log_width() != logwidth0 { None } else { - let int_out_type = INT_TYPES[logwidth1 as usize].to_owned(); + let int_out_type = INT_TYPES[logwidth0 as usize].to_owned(); let sum_type = sum_with_error(int_out_type.clone()); let err_value = || { let err_val = ConstError { @@ -905,7 +903,7 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { err_value() } else { let (_, rval) = divmod_s(nval, mval); - Value::extension(ConstInt::new_u(logwidth1, rval).unwrap()) + Value::extension(ConstInt::new_u(logwidth0, rval).unwrap()) }; Some(vec![(0.into(), out_const)]) } @@ -915,19 +913,19 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::imod_s => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n, m): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; let nval = n.value_s(); let mval = m.value_u(); - if n.log_width() != logwidth0 || m.log_width() != logwidth1 || mval == 0 { + if n.log_width() != logwidth0 || m.log_width() != logwidth0 || mval == 0 { None } else { let (_, rval) = divmod_s(nval, mval); - let r = Value::extension(ConstInt::new_u(logwidth1, rval).unwrap()); + let r = Value::extension(ConstInt::new_u(logwidth0, rval).unwrap()); Some(vec![(0.into(), r)]) } }, @@ -1052,13 +1050,13 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::ishl => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n0, n1): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; - if n0.log_width() != logwidth0 || n1.log_width() != logwidth1 { + if n0.log_width() != logwidth0 || n1.log_width() != logwidth0 { None } else { Some(vec![( @@ -1079,13 +1077,13 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::ishr => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n0, n1): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; - if n0.log_width() != logwidth0 || n1.log_width() != logwidth1 { + if n0.log_width() != logwidth0 || n1.log_width() != logwidth0 { None } else { Some(vec![( @@ -1101,13 +1099,13 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::irotl => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n0, n1): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; - if n0.log_width() != logwidth0 || n1.log_width() != logwidth1 { + if n0.log_width() != logwidth0 || n1.log_width() != logwidth0 { None } else { let n = n0.value_u(); @@ -1130,13 +1128,13 @@ pub(super) fn set_fold(op: &IntOpDef, def: &mut OpDef) { IntOpDef::irotr => Folder { folder: Box::new( |type_args: &[TypeArg], consts: &[(IncomingPort, Value)]| -> ConstFoldResult { - let [arg0, arg1] = type_args else { + let [arg0] = type_args else { return None; }; let logwidth0: u8 = get_log_width(arg0).ok()?; - let logwidth1: u8 = get_log_width(arg1).ok()?; + let (n0, n1): (&ConstInt, &ConstInt) = get_pair_of_input_values(consts)?; - if n0.log_width() != logwidth0 || n1.log_width() != logwidth1 { + if n0.log_width() != logwidth0 || n1.log_width() != logwidth0 { None } else { let n = n0.value_u(); diff --git a/hugr-passes/src/const_fold/test.rs b/hugr-passes/src/const_fold/test.rs index 68960591e..28f43f31e 100644 --- a/hugr-passes/src/const_fold/test.rs +++ b/hugr-passes/src/const_fold/test.rs @@ -885,19 +885,16 @@ fn test_fold_imul() { #[test] fn test_fold_idivmod_checked_u() { // pseudocode: - // x0, x1 := int_u<5>(20), int_u<3>(0) + // x0, x1 := int_u<5>(20), int_u<5>(0) // x2 := idivmod_checked_u(x0, x1) // output x2 == error - let intpair: TypeRowRV = vec![INT_TYPES[5].clone(), INT_TYPES[3].clone()].into(); + let intpair: TypeRowRV = vec![INT_TYPES[5].clone(), INT_TYPES[5].clone()].into(); let sum_type = sum_with_error(Type::new_tuple(intpair)); let mut build = DFGBuilder::new(noargfn(vec![sum_type.clone().into()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_u(5, 20).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 0).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 0).unwrap())); let x2 = build - .add_dataflow_op( - IntOpDef::idivmod_checked_u.with_two_log_widths(5, 3), - [x0, x1], - ) + .add_dataflow_op(IntOpDef::idivmod_checked_u.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -922,52 +919,44 @@ fn test_fold_idivmod_checked_u() { #[test] fn test_fold_idivmod_u() { // pseudocode: - // x0, x1 := int_u<5>(20), int_u<3>(3); + // x0, x1 := int_u<3>(20), int_u<3>(3); // x2, x3 := idivmod_u(x0, x1); // 6, 2 - // x4 := iwiden_u<3,5>(x3); // 2 - // x5 := iadd<5>(x2, x4); // 8 - // output x5 == int_u<5>(8); - let mut build = DFGBuilder::new(noargfn(vec![INT_TYPES[5].clone()])).unwrap(); - let x0 = build.add_load_const(Value::extension(ConstInt::new_u(5, 20).unwrap())); + // x4 := iadd<3>(x2, x3); // 8 + // output x4 == int_u<5>(8); + let mut build = DFGBuilder::new(noargfn(vec![INT_TYPES[3].clone()])).unwrap(); + let x0 = build.add_load_const(Value::extension(ConstInt::new_u(3, 20).unwrap())); let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 3).unwrap())); let [x2, x3] = build - .add_dataflow_op(IntOpDef::idivmod_u.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::idivmod_u.with_log_width(3), [x0, x1]) .unwrap() .outputs_arr(); - let [x4] = build - .add_dataflow_op(IntOpDef::iwiden_u.with_two_log_widths(3, 5), [x3]) - .unwrap() - .outputs_arr(); - let x5 = build - .add_dataflow_op(IntOpDef::iadd.with_log_width(5), [x2, x4]) + let x4 = build + .add_dataflow_op(IntOpDef::iadd.with_log_width(3), [x2, x3]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), arithmetic::int_types::EXTENSION.to_owned(), ]) .unwrap(); - let mut h = build.finish_hugr_with_outputs(x5.outputs(), ®).unwrap(); + let mut h = build.finish_hugr_with_outputs(x4.outputs(), ®).unwrap(); constant_fold_pass(&mut h, ®); - let expected = Value::extension(ConstInt::new_u(5, 8).unwrap()); + let expected = Value::extension(ConstInt::new_u(3, 8).unwrap()); assert_fully_folded(&h, &expected); } #[test] fn test_fold_idivmod_checked_s() { // pseudocode: - // x0, x1 := int_s<5>(-20), int_u<3>(0) + // x0, x1 := int_s<5>(-20), int_u<5>(0) // x2 := idivmod_checked_s(x0, x1) // output x2 == error - let intpair: TypeRowRV = vec![INT_TYPES[5].clone(), INT_TYPES[3].clone()].into(); + let intpair: TypeRowRV = vec![INT_TYPES[5].clone(), INT_TYPES[5].clone()].into(); let sum_type = sum_with_error(Type::new_tuple(intpair)); let mut build = DFGBuilder::new(noargfn(vec![sum_type.clone().into()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_s(5, -20).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 0).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 0).unwrap())); let x2 = build - .add_dataflow_op( - IntOpDef::idivmod_checked_s.with_two_log_widths(5, 3), - [x0, x1], - ) + .add_dataflow_op(IntOpDef::idivmod_checked_s.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -1002,7 +991,7 @@ fn test_fold_idivmod_s(#[case] a: i64, #[case] b: u64, #[case] c: i64) { let x0 = build.add_load_const(Value::extension(ConstInt::new_s(6, a).unwrap())); let x1 = build.add_load_const(Value::extension(ConstInt::new_u(6, b).unwrap())); let [x2, x3] = build - .add_dataflow_op(IntOpDef::idivmod_s.with_two_log_widths(6, 6), [x0, x1]) + .add_dataflow_op(IntOpDef::idivmod_s.with_log_width(6), [x0, x1]) .unwrap() .outputs_arr(); let x4 = build @@ -1022,15 +1011,15 @@ fn test_fold_idivmod_s(#[case] a: i64, #[case] b: u64, #[case] c: i64) { #[test] fn test_fold_idiv_checked_u() { // pseudocode: - // x0, x1 := int_u<5>(20), int_u<3>(0) + // x0, x1 := int_u<5>(20), int_u<5>(0) // x2 := idiv_checked_u(x0, x1) // output x2 == error let sum_type = sum_with_error(INT_TYPES[5].to_owned()); let mut build = DFGBuilder::new(noargfn(vec![sum_type.clone().into()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_u(5, 20).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 0).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 0).unwrap())); let x2 = build - .add_dataflow_op(IntOpDef::idiv_checked_u.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::idiv_checked_u.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -1055,14 +1044,14 @@ fn test_fold_idiv_checked_u() { #[test] fn test_fold_idiv_u() { // pseudocode: - // x0, x1 := int_u<5>(20), int_u<3>(3); + // x0, x1 := int_u<5>(20), int_u<5>(3); // x2 := idiv_u(x0, x1); // output x2 == int_u<5>(6); let mut build = DFGBuilder::new(noargfn(vec![INT_TYPES[5].clone()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_u(5, 20).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 3).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 3).unwrap())); let x2 = build - .add_dataflow_op(IntOpDef::idiv_u.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::idiv_u.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -1078,15 +1067,15 @@ fn test_fold_idiv_u() { #[test] fn test_fold_imod_checked_u() { // pseudocode: - // x0, x1 := int_u<5>(20), int_u<3>(0) + // x0, x1 := int_u<5>(20), int_u<5>(0) // x2 := imod_checked_u(x0, x1) // output x2 == error - let sum_type = sum_with_error(INT_TYPES[3].to_owned()); + let sum_type = sum_with_error(INT_TYPES[5].to_owned()); let mut build = DFGBuilder::new(noargfn(vec![sum_type.clone().into()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_u(5, 20).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 0).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 0).unwrap())); let x2 = build - .add_dataflow_op(IntOpDef::imod_checked_u.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::imod_checked_u.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -1111,14 +1100,14 @@ fn test_fold_imod_checked_u() { #[test] fn test_fold_imod_u() { // pseudocode: - // x0, x1 := int_u<5>(20), int_u<3>(3); + // x0, x1 := int_u<5>(20), int_u<5>(3); // x2 := imod_u(x0, x1); // output x2 == int_u<3>(2); - let mut build = DFGBuilder::new(noargfn(vec![INT_TYPES[3].clone()])).unwrap(); + let mut build = DFGBuilder::new(noargfn(vec![INT_TYPES[5].clone()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_u(5, 20).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 3).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 3).unwrap())); let x2 = build - .add_dataflow_op(IntOpDef::imod_u.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::imod_u.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -1127,22 +1116,22 @@ fn test_fold_imod_u() { .unwrap(); let mut h = build.finish_hugr_with_outputs(x2.outputs(), ®).unwrap(); constant_fold_pass(&mut h, ®); - let expected = Value::extension(ConstInt::new_u(3, 2).unwrap()); + let expected = Value::extension(ConstInt::new_u(5, 2).unwrap()); assert_fully_folded(&h, &expected); } #[test] fn test_fold_idiv_checked_s() { // pseudocode: - // x0, x1 := int_s<5>(-20), int_u<3>(0) + // x0, x1 := int_s<5>(-20), int_u<5>(0) // x2 := idiv_checked_s(x0, x1) // output x2 == error let sum_type = sum_with_error(INT_TYPES[5].to_owned()); let mut build = DFGBuilder::new(noargfn(vec![sum_type.clone().into()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_s(5, -20).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 0).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 0).unwrap())); let x2 = build - .add_dataflow_op(IntOpDef::idiv_checked_s.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::idiv_checked_s.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -1167,14 +1156,14 @@ fn test_fold_idiv_checked_s() { #[test] fn test_fold_idiv_s() { // pseudocode: - // x0, x1 := int_s<5>(-20), int_u<3>(3); + // x0, x1 := int_s<5>(-20), int_u<5>(3); // x2 := idiv_s(x0, x1); // output x2 == int_s<5>(-7); let mut build = DFGBuilder::new(noargfn(vec![INT_TYPES[5].clone()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_s(5, -20).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 3).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 3).unwrap())); let x2 = build - .add_dataflow_op(IntOpDef::idiv_s.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::idiv_s.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -1190,15 +1179,15 @@ fn test_fold_idiv_s() { #[test] fn test_fold_imod_checked_s() { // pseudocode: - // x0, x1 := int_s<5>(-20), int_u<3>(0) + // x0, x1 := int_s<5>(-20), int_u<5>(0) // x2 := imod_checked_u(x0, x1) // output x2 == error - let sum_type = sum_with_error(INT_TYPES[3].to_owned()); + let sum_type = sum_with_error(INT_TYPES[5].to_owned()); let mut build = DFGBuilder::new(noargfn(vec![sum_type.clone().into()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_s(5, -20).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 0).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 0).unwrap())); let x2 = build - .add_dataflow_op(IntOpDef::imod_checked_s.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::imod_checked_s.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -1223,14 +1212,14 @@ fn test_fold_imod_checked_s() { #[test] fn test_fold_imod_s() { // pseudocode: - // x0, x1 := int_s<5>(-20), int_u<3>(3); + // x0, x1 := int_s<5>(-20), int_u<5>(3); // x2 := imod_s(x0, x1); - // output x2 == int_u<3>(1); - let mut build = DFGBuilder::new(noargfn(vec![INT_TYPES[3].clone()])).unwrap(); + // output x2 == int_u<5>(1); + let mut build = DFGBuilder::new(noargfn(vec![INT_TYPES[5].clone()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_s(5, -20).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 3).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 3).unwrap())); let x2 = build - .add_dataflow_op(IntOpDef::imod_s.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::imod_s.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -1239,7 +1228,7 @@ fn test_fold_imod_s() { .unwrap(); let mut h = build.finish_hugr_with_outputs(x2.outputs(), ®).unwrap(); constant_fold_pass(&mut h, ®); - let expected = Value::extension(ConstInt::new_u(3, 1).unwrap()); + let expected = Value::extension(ConstInt::new_u(5, 1).unwrap()); assert_fully_folded(&h, &expected); } @@ -1364,9 +1353,9 @@ fn test_fold_ishl() { // output x2 == int_u<5>(112); let mut build = DFGBuilder::new(noargfn(vec![INT_TYPES[5].clone()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_s(5, 14).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 3).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 3).unwrap())); let x2 = build - .add_dataflow_op(IntOpDef::ishl.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::ishl.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -1387,9 +1376,9 @@ fn test_fold_ishr() { // output x2 == int_u<5>(1); let mut build = DFGBuilder::new(noargfn(vec![INT_TYPES[5].clone()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_s(5, 14).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 3).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 3).unwrap())); let x2 = build - .add_dataflow_op(IntOpDef::ishr.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::ishr.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -1410,9 +1399,9 @@ fn test_fold_irotl() { // output x2 == int_u<5>(2^30 + 2^31 + 1); let mut build = DFGBuilder::new(noargfn(vec![INT_TYPES[5].clone()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_s(5, 14).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 61).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 61).unwrap())); let x2 = build - .add_dataflow_op(IntOpDef::irotl.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::irotl.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), @@ -1433,9 +1422,9 @@ fn test_fold_irotr() { // output x2 == int_u<5>(2^30 + 2^31 + 1); let mut build = DFGBuilder::new(noargfn(vec![INT_TYPES[5].clone()])).unwrap(); let x0 = build.add_load_const(Value::extension(ConstInt::new_s(5, 14).unwrap())); - let x1 = build.add_load_const(Value::extension(ConstInt::new_u(3, 3).unwrap())); + let x1 = build.add_load_const(Value::extension(ConstInt::new_u(5, 3).unwrap())); let x2 = build - .add_dataflow_op(IntOpDef::irotr.with_two_log_widths(5, 3), [x0, x1]) + .add_dataflow_op(IntOpDef::irotr.with_log_width(5), [x0, x1]) .unwrap(); let reg = ExtensionRegistry::try_new([ PRELUDE.to_owned(), diff --git a/hugr-py/src/hugr/node_port.py b/hugr-py/src/hugr/node_port.py index 0f268fe88..556692aca 100644 --- a/hugr-py/src/hugr/node_port.py +++ b/hugr-py/src/hugr/node_port.py @@ -164,24 +164,60 @@ def _index( ) -> OutPort | Iterator[OutPort]: match index: case PortOffset(index): - if self._num_out_ports is not None and index >= self._num_out_ports: - msg = "Index out of range" - raise IndexError(msg) + index = self._normalize_index(index) return self.out(index) case slice(): start = index.start or 0 - stop = index.stop or self._num_out_ports + stop = index.stop if index.stop is not None else self._num_out_ports if stop is None: msg = ( f"{self} does not have a fixed number of output ports. " "Iterating over all output ports is not supported." ) raise ValueError(msg) + + start = self._normalize_index(start) + stop = self._normalize_index(stop, allow_eq_len=True) step = index.step or 1 + return (self[i] for i in range(start, stop, step)) case tuple(xs): return (self[i] for i in xs) + def _normalize_index(self, index: int, allow_eq_len: bool = False) -> int: + """Given an index passed to `__getitem__`, normalize it to be within the + range of output ports. + + Args: + index: index to normalize. + allow_eq_len: whether to allow the index to be equal to the number of + output ports. + + Returns: + Normalized index. + + Raises: + IndexError: if the index is out of range. + """ + msg = f"Index {index} out of range" + + if self._num_out_ports is not None: + if index > self._num_out_ports: + raise IndexError(msg) + if index == self._num_out_ports and not allow_eq_len: + raise IndexError(msg) + if index < -self._num_out_ports: + raise IndexError(msg) + else: + if index < 0: + raise IndexError(msg) + + if index >= 0: + return index + else: + assert self._num_out_ports is not None + return self._num_out_ports + index + def to_node(self) -> Node: return self diff --git a/hugr-py/src/hugr/ops.py b/hugr-py/src/hugr/ops.py index 809696095..e00148eb8 100644 --- a/hugr-py/src/hugr/ops.py +++ b/hugr-py/src/hugr/ops.py @@ -4,7 +4,7 @@ from dataclasses import dataclass, field from functools import cached_property -from typing import TYPE_CHECKING, Protocol, TypeVar, runtime_checkable +from typing import TYPE_CHECKING, ClassVar, Protocol, TypeVar, runtime_checkable from typing_extensions import Self @@ -398,11 +398,12 @@ class RegisteredOp(AsExtOp): """ #: Known operation definition. - const_op_def: ext.OpDef # must be initialised by register_op + const_op_def: ClassVar[ext.OpDef] # may be set by registered_op decorator. - def op_def(self) -> ext.OpDef: + @classmethod + def op_def(cls) -> ext.OpDef: # override for AsExtOp.op_def - return self.const_op_def + return cls.const_op_def @dataclass() diff --git a/hugr-py/src/hugr/serialization/extension.py b/hugr-py/src/hugr/serialization/extension.py index 7ce2ef481..291f7e5c8 100644 --- a/hugr-py/src/hugr/serialization/extension.py +++ b/hugr-py/src/hugr/serialization/extension.py @@ -97,7 +97,7 @@ class OpDef(ConfiguredBaseModel, populate_by_name=True): misc: dict[str, Any] | None = None signature: PolyFuncType | None = None binary: bool = False - lower_funcs: list[FixedHugr] + lower_funcs: list[FixedHugr] = pd.Field(default_factory=list) def deserialize(self, extension: ext.Extension) -> ext.OpDef: return extension.add_op_def( diff --git a/hugr-py/src/hugr/std/__init__.py b/hugr-py/src/hugr/std/__init__.py index f01d3d421..f3dd70167 100644 --- a/hugr-py/src/hugr/std/__init__.py +++ b/hugr-py/src/hugr/std/__init__.py @@ -1 +1,13 @@ """Types and operations from the standard extension set.""" + +import pkgutil + +from hugr.ext import Extension +from hugr.serialization.extension import Extension as PdExtension + + +def _load_extension(name: str) -> Extension: + replacement = name.replace(".", "/") + json_str = pkgutil.get_data(__name__, f"_json_defs/{replacement}.json") + assert json_str is not None + return PdExtension.model_validate_json(json_str).deserialize() diff --git a/hugr-py/src/hugr/std/_json_defs/README.md b/hugr-py/src/hugr/std/_json_defs/README.md new file mode 100644 index 000000000..af064f00f --- /dev/null +++ b/hugr-py/src/hugr/std/_json_defs/README.md @@ -0,0 +1,2 @@ +The files in this directory are generated and copied in, don't edit by hand. See +repository justfile `gen-extensions` command. diff --git a/hugr-py/src/hugr/std/_json_defs/arithmetic/conversions.json b/hugr-py/src/hugr/std/_json_defs/arithmetic/conversions.json new file mode 100644 index 000000000..c23cba7c6 --- /dev/null +++ b/hugr-py/src/hugr/std/_json_defs/arithmetic/conversions.json @@ -0,0 +1,222 @@ +{ + "version": "0.1.0", + "name": "arithmetic.conversions", + "extension_reqs": [ + "arithmetic.float.types", + "arithmetic.int.types" + ], + "types": {}, + "values": {}, + "operations": { + "convert_s": { + "extension": "arithmetic.conversions", + "name": "convert_s", + "description": "signed int to float", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": 7 + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "convert_u": { + "extension": "arithmetic.conversions", + "name": "convert_u", + "description": "unsigned int to float", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": 7 + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "trunc_s": { + "extension": "arithmetic.conversions", + "name": "trunc_s", + "description": "float to signed int", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": 7 + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Sum", + "s": "General", + "rows": [ + [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + [ + { + "t": "Opaque", + "extension": "prelude", + "id": "error", + "args": [], + "bound": "C" + } + ] + ] + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "trunc_u": { + "extension": "arithmetic.conversions", + "name": "trunc_u", + "description": "float to unsigned int", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": 7 + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Sum", + "s": "General", + "rows": [ + [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + [ + { + "t": "Opaque", + "extension": "prelude", + "id": "error", + "args": [], + "bound": "C" + } + ] + ] + } + ], + "extension_reqs": [] + } + }, + "binary": false + } + } +} diff --git a/hugr-py/src/hugr/std/_json_defs/arithmetic/float.json b/hugr-py/src/hugr/std/_json_defs/arithmetic/float.json new file mode 100644 index 000000000..8563fe57b --- /dev/null +++ b/hugr-py/src/hugr/std/_json_defs/arithmetic/float.json @@ -0,0 +1,593 @@ +{ + "version": "0.1.0", + "name": "arithmetic.float", + "extension_reqs": [ + "arithmetic.int.types" + ], + "types": {}, + "values": {}, + "operations": { + "fabs": { + "extension": "arithmetic.float", + "name": "fabs", + "description": "absolute value", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "fadd": { + "extension": "arithmetic.float", + "name": "fadd", + "description": "addition", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "fceil": { + "extension": "arithmetic.float", + "name": "fceil", + "description": "ceiling", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "fdiv": { + "extension": "arithmetic.float", + "name": "fdiv", + "description": "division", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "feq": { + "extension": "arithmetic.float", + "name": "feq", + "description": "equality test", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Sum", + "s": "Unit", + "size": 2 + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "ffloor": { + "extension": "arithmetic.float", + "name": "ffloor", + "description": "floor", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "fge": { + "extension": "arithmetic.float", + "name": "fge", + "description": "\"greater than or equal\"", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Sum", + "s": "Unit", + "size": 2 + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "fgt": { + "extension": "arithmetic.float", + "name": "fgt", + "description": "\"greater than\"", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Sum", + "s": "Unit", + "size": 2 + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "fle": { + "extension": "arithmetic.float", + "name": "fle", + "description": "\"less than or equal\"", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Sum", + "s": "Unit", + "size": 2 + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "flt": { + "extension": "arithmetic.float", + "name": "flt", + "description": "\"less than\"", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Sum", + "s": "Unit", + "size": 2 + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "fmax": { + "extension": "arithmetic.float", + "name": "fmax", + "description": "maximum", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "fmin": { + "extension": "arithmetic.float", + "name": "fmin", + "description": "minimum", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "fmul": { + "extension": "arithmetic.float", + "name": "fmul", + "description": "multiplication", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "fne": { + "extension": "arithmetic.float", + "name": "fne", + "description": "inequality test", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Sum", + "s": "Unit", + "size": 2 + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "fneg": { + "extension": "arithmetic.float", + "name": "fneg", + "description": "negation", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "fsub": { + "extension": "arithmetic.float", + "name": "fsub", + "description": "subtraction", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "ftostring": { + "extension": "arithmetic.float", + "name": "ftostring", + "description": "string representation", + "signature": { + "params": [], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.float.types", + "id": "float64", + "args": [], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "prelude", + "id": "string", + "args": [], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + } + } +} diff --git a/hugr-py/src/hugr/std/_json_defs/arithmetic/float/types.json b/hugr-py/src/hugr/std/_json_defs/arithmetic/float/types.json new file mode 100644 index 000000000..d590a83f4 --- /dev/null +++ b/hugr-py/src/hugr/std/_json_defs/arithmetic/float/types.json @@ -0,0 +1,19 @@ +{ + "version": "0.1.0", + "name": "arithmetic.float.types", + "extension_reqs": [], + "types": { + "float64": { + "extension": "arithmetic.float.types", + "name": "float64", + "params": [], + "description": "64-bit IEEE 754-2019 floating-point value", + "bound": { + "b": "Explicit", + "bound": "C" + } + } + }, + "values": {}, + "operations": {} +} diff --git a/hugr-py/src/hugr/std/_json_defs/arithmetic/int.json b/hugr-py/src/hugr/std/_json_defs/arithmetic/int.json new file mode 100644 index 000000000..6eb546736 --- /dev/null +++ b/hugr-py/src/hugr/std/_json_defs/arithmetic/int.json @@ -0,0 +1,3142 @@ +{ + "version": "0.1.0", + "name": "arithmetic.int", + "extension_reqs": [ + "arithmetic.int.types" + ], + "types": {}, + "values": {}, + "operations": { + "iabs": { + "extension": "arithmetic.int", + "name": "iabs", + "description": "convert signed to unsigned by taking absolute value", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": 7 + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "iadd": { + "extension": "arithmetic.int", + "name": "iadd", + "description": "addition modulo 2^N (signed and unsigned versions are the same op)", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": 7 + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "iand": { + "extension": "arithmetic.int", + "name": "iand", + "description": "bitwise AND", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": 7 + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "idiv_checked_s": { + "extension": "arithmetic.int", + "name": "idiv_checked_s", + "description": "as idivmod_checked_s but discarding the second output", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": 7 + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "output": [ + { + "t": "Sum", + "s": "General", + "rows": [ + [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + [ + { + "t": "Opaque", + "extension": "prelude", + "id": "error", + "args": [], + "bound": "C" + } + ] + ] + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "idiv_checked_u": { + "extension": "arithmetic.int", + "name": "idiv_checked_u", + "description": "as idivmod_checked_u but discarding the second output", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": 7 + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "output": [ + { + "t": "Sum", + "s": "General", + "rows": [ + [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + [ + { + "t": "Opaque", + "extension": "prelude", + "id": "error", + "args": [], + "bound": "C" + } + ] + ] + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "idiv_s": { + "extension": "arithmetic.int", + "name": "idiv_s", + "description": "as idivmod_s but discarding the second output", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": 7 + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "idiv_u": { + "extension": "arithmetic.int", + "name": "idiv_u", + "description": "as idivmod_u but discarding the second output", + "signature": { + "params": [ + { + "tp": "BoundedNat", + "bound": 7 + } + ], + "body": { + "input": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + }, + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "output": [ + { + "t": "Opaque", + "extension": "arithmetic.int.types", + "id": "int", + "args": [ + { + "tya": "Variable", + "idx": 0, + "cached_decl": { + "tp": "BoundedNat", + "bound": 7 + } + } + ], + "bound": "C" + } + ], + "extension_reqs": [] + } + }, + "binary": false + }, + "idivmod_checked_s": { + "extension": "arithmetic.int", + "name": "idivmod_checked_s", + "description": "given signed integer -2^{N-1} <= n < 2^{N-1} and unsigned 0 <= m < 2^N, generates signed q and unsigned r where q*m+r=n, 0<=r tys.ExtType: @@ -72,35 +67,30 @@ def to_value(self) -> val.Extension: ) -INT_OPS_EXTENSION = ext.Extension("arithmetic.int", ext.Version(0, 1, 0)) +INT_OPS_EXTENSION = _load_extension("arithmetic.int") -@INT_OPS_EXTENSION.register_op( - signature=ext.OpDefSig( - tys.FunctionType([_int_tv(0), _int_tv(1)], [_int_tv(0), _int_tv(1)]) - ), -) @dataclass(frozen=True) -class idivmod_u(RegisteredOp): +class _DivModDef(RegisteredOp): """DivMod operation, has two inputs and two outputs.""" - arg1: int = 5 - arg2: int = 5 + width: int = 5 + const_op_def: ClassVar[ext.OpDef] = INT_OPS_EXTENSION.operations["idivmod_u"] def type_args(self) -> list[tys.TypeArg]: - return [tys.BoundedNatArg(n=self.arg1), tys.BoundedNatArg(n=self.arg2)] + return [tys.BoundedNatArg(n=self.width)] def cached_signature(self) -> tys.FunctionType | None: - row: list[tys.Type] = [int_t(self.arg1), int_t(self.arg2)] + row: list[tys.Type] = [int_t(self.width)] * 2 return tys.FunctionType.endo(row) @classmethod def from_ext(cls, custom: ExtOp) -> Self | None: - if custom.op_def() != cls.const_op_def: + if custom.op_def() != cls.op_def(): return None match custom.args: - case [tys.BoundedNatArg(n=a1), tys.BoundedNatArg(n=a2)]: - return cls(arg1=a1, arg2=a2) + case [tys.BoundedNatArg(n=a1)]: + return cls(width=a1) case _: msg = f"Invalid args: {custom.args}" raise AsExtOp.InvalidExtOp(msg) @@ -110,4 +100,4 @@ def __call__(self, a: ComWire, b: ComWire) -> Command: #: DivMod operation. -DivMod = idivmod_u() +DivMod = _DivModDef() diff --git a/hugr-py/src/hugr/std/logic.py b/hugr-py/src/hugr/std/logic.py index d104a64b8..05524c31c 100644 --- a/hugr-py/src/hugr/std/logic.py +++ b/hugr-py/src/hugr/std/logic.py @@ -3,26 +3,25 @@ from __future__ import annotations from dataclasses import dataclass -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, ClassVar -from hugr import ext, tys from hugr.ops import Command, DataflowOp, RegisteredOp +from hugr.std import _load_extension if TYPE_CHECKING: + from hugr import ext from hugr.ops import ComWire -EXTENSION = ext.Extension("logic", ext.Version(0, 1, 0)) +EXTENSION = _load_extension("logic") -@EXTENSION.register_op( - name="Not", - signature=ext.OpDefSig(tys.FunctionType.endo([tys.Bool])), -) @dataclass(frozen=True) class _NotOp(RegisteredOp): """Logical NOT operation.""" + const_op_def: ClassVar[ext.OpDef] = EXTENSION.operations["Not"] + def __call__(self, a: ComWire) -> Command: return DataflowOp.__call__(self, a) diff --git a/hugr-py/tests/test_nodes.py b/hugr-py/tests/test_nodes.py new file mode 100644 index 000000000..7fc1d30db --- /dev/null +++ b/hugr-py/tests/test_nodes.py @@ -0,0 +1,37 @@ +import pytest + +from hugr.node_port import Node, OutPort + + +def test_index(): + n = Node(0, _num_out_ports=3) + assert n[0] == OutPort(n, 0) + assert n[1] == OutPort(n, 1) + assert n[2] == OutPort(n, 2) + assert n[-1] == OutPort(n, 2) + + with pytest.raises(IndexError, match="Index 3 out of range"): + _ = n[3] + + with pytest.raises(IndexError, match="Index -8 out of range"): + _ = n[-8] + + +def test_slices(): + n = Node(0, _num_out_ports=3) + all_ports = [OutPort(n, i) for i in range(3)] + + assert list(n) == all_ports + assert list(n[:0]) == [] + assert list(n[0:0]) == [] + assert list(n[0:1]) == [OutPort(n, 0)] + assert list(n[1:2]) == [OutPort(n, 1)] + assert list(n[:]) == all_ports + assert list(n[0:]) == all_ports + assert list(n[:3]) == all_ports + assert list(n[0:3]) == all_ports + assert list(n[-1:]) == [OutPort(n, 2)] + assert list(n[-3:]) == all_ports + + with pytest.raises(IndexError, match="Index -4 out of range"): + _ = n[-4:] diff --git a/justfile b/justfile index 3194afa70..2f8beaec6 100644 --- a/justfile +++ b/justfile @@ -58,7 +58,7 @@ update-schema: # Generate serialized declarations for the standard extensions and prelude. gen-extensions: cargo run -p hugr-cli gen-extensions -o specification/std_extensions - + cp -r specification/std_extensions/* hugr-py/src/hugr/std/_json_defs/ build-py-docs: cd hugr-py/docs && ./build.sh diff --git a/specification/hugr.md b/specification/hugr.md index e2bc960ee..370aba99c 100644 --- a/specification/hugr.md +++ b/specification/hugr.md @@ -1761,39 +1761,40 @@ Comparisons: Other operations: -| Name | Inputs | Outputs | Meaning | -| ---------------------- | ------------------ | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `imax_u` | `int`, `int` | `int` | maximum of unsigned integers | -| `imax_s` | `int`, `int` | `int` | maximum of signed integers | -| `imin_u` | `int`, `int` | `int` | minimum of unsigned integers | -| `imin_s` | `int`, `int` | `int` | minimum of signed integers | -| `iadd` | `int`, `int` | `int` | addition modulo 2^N (signed and unsigned versions are the same op) | -| `isub` | `int`, `int` | `int` | subtraction modulo 2^N (signed and unsigned versions are the same op) | -| `ineg` | `int` | `int` | negation modulo 2^N (signed and unsigned versions are the same op) | -| `imul` | `int`, `int` | `int` | multiplication modulo 2^N (signed and unsigned versions are the same op) | -| `idivmod_checked_u`( \* ) | `int`, `int` | `Sum(#(int, int), #(ErrorType))` | given unsigned integers 0 \<= n \< 2^N, 0 \<= m \< 2^M, generates unsigned q, r where q\*m+r=n, 0\<=r\` | `int`, `int` | `(int, int)` | given unsigned integers 0 \<= n \< 2^N, 0 \<= m \< 2^M, generates unsigned q, r where q\*m+r=n, 0\<=r\`( \* ) | `int`, `int` | `Sum(#(int, int), #(ErrorType))` | given signed integer -2^{N-1} \<= n \< 2^{N-1} and unsigned 0 \<= m \< 2^M, generates signed q and unsigned r where q\*m+r=n, 0\<=r\`( \* ) | `int`, `int` | `(int, int)` | given signed integer -2^{N-1} \<= n \< 2^{N-1} and unsigned 0 \<= m \< 2^M, generates signed q and unsigned r where q\*m+r=n, 0\<=r\` ( \* ) | `int`, `int` | `Sum(#(int),#( ErrorType))` | as `idivmod_checked_u` but discarding the second output | -| `idiv_u` | `int`, `int` | `int` | as `idivmod_u` but discarding the second output | -| `imod_checked_u` ( \* ) | `int`, `int` | `Sum(#(int), #(ErrorType))` | as `idivmod_checked_u` but discarding the first output | -| `imod_u` | `int`, `int` | `int` | as `idivmod_u` but discarding the first output | -| `idiv_checked_s`( \* ) | `int`, `int` | `Sum(#(int), #(ErrorType))` | as `idivmod_checked_s` but discarding the second output | -| `idiv_s` | `int`, `int` | `int` | as `idivmod_s` but discarding the second output | -| `imod_checked_s`( \* ) | `int`, `int` | `Sum(#(int), #(ErrorType))` | as `idivmod_checked_s` but discarding the first output | -| `imod_s` | `int`, `int` | `int` | as `idivmod_s` but discarding the first output | -| `iabs` | `int` | `int` | convert signed to unsigned by taking absolute value | -| `iand` | `int`, `int` | `int` | bitwise AND | -| `ior` | `int`, `int` | `int` | bitwise OR | -| `ixor` | `int`, `int` | `int` | bitwise XOR | -| `inot` | `int` | `int` | bitwise NOT | -| `ishl`( \* ) | `int`, `int` | `int` | shift first input left by k bits where k is unsigned interpretation of second input (leftmost bits dropped, rightmost bits set to zero) | -| `ishr`( \* ) | `int`, `int` | `int` | shift first input right by k bits where k is unsigned interpretation of second input (rightmost bits dropped, leftmost bits set to zero) | -| `irotl`( \* ) | `int`, `int` | `int` | rotate first input left by k bits where k is unsigned interpretation of second input (leftmost bits replace rightmost bits) | -| `irotr`( \* ) | `int`, `int` | `int` | rotate first input right by k bits where k is unsigned interpretation of second input (rightmost bits replace leftmost bits) | -| `itostring_u` | `int` | `string` | decimal string representation of unsigned integer | -| `itostring_s` | `int` | `string` | decimal string representation of signed integer | +| Name | Inputs | Outputs | Meaning | +|------------------------------|--------------------|----------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `imax_u` | `int`, `int` | `int` | maximum of unsigned integers | +| `imax_s` | `int`, `int` | `int` | maximum of signed integers | +| `imin_u` | `int`, `int` | `int` | minimum of unsigned integers | +| `imin_s` | `int`, `int` | `int` | minimum of signed integers | +| `iadd` | `int`, `int` | `int` | addition modulo 2^N (signed and unsigned versions are the same op) | +| `isub` | `int`, `int` | `int` | subtraction modulo 2^N (signed and unsigned versions are the same op) | +| `ineg` | `int` | `int` | negation modulo 2^N (signed and unsigned versions are the same op) | +| `imul` | `int`, `int` | `int` | multiplication modulo 2^N (signed and unsigned versions are the same op) | +| `idivmod_checked_u`( \* ) | `int`, `int` | `Sum(#(int, int), #(ErrorType))` | given unsigned integers 0 \<= n \< 2^N, 0 \<= m \< 2^N, generates unsigned q, r where q\*m+r=n, 0\<=r\` | `int`, `int` | `(int, int)` | given unsigned integers 0 \<= n \< 2^N, 0 \<= m \< 2^N, generates unsigned q, r where q\*m+r=n, 0\<=r\`( \* ) | `int`, `int` | `Sum(#(int, int), #(ErrorType))` | given signed integer -2^{N-1} \<= n \< 2^{N-1} and unsigned 0 \<= m \< 2^N, generates signed q and unsigned r where q\*m+r=n, 0\<=r\`( \* ) | `int`, `int` | `(int, int)` | given signed integer -2^{N-1} \<= n \< 2^{N-1} and unsigned 0 \<= m \< 2^N, generates signed q and unsigned r where q\*m+r=n, 0\<=r\` ( \* ) | `int`, `int` | `Sum(#(int),#( ErrorType))` | as `idivmod_checked_u` but discarding the second output | +| `idiv_u` | `int`, `int` | `int` | as `idivmod_u` but discarding the second output | +| `imod_checked_u` ( \* ) | `int`, `int` | `Sum(#(int), #(ErrorType))` | as `idivmod_checked_u` but discarding the first output | +| `imod_u` | `int`, `int` | `int` | as `idivmod_u` but discarding the first output | +| `idiv_checked_s`( \* ) | `int`, `int` | `Sum(#(int), #(ErrorType))` | as `idivmod_checked_s` but discarding the second output | +| `idiv_s` | `int`, `int` | `int` | as `idivmod_s` but discarding the second output | +| `imod_checked_s`( \* ) | `int`, `int` | `Sum(#(int), #(ErrorType))` | as `idivmod_checked_s` but discarding the first output | +| `imod_s` | `int`, `int` | `int` | as `idivmod_s` but discarding the first output | +| `iabs` | `int` | `int` | convert signed to unsigned by taking absolute value | +| `iand` | `int`, `int` | `int` | bitwise AND | +| `ior` | `int`, `int` | `int` | bitwise OR | +| `ixor` | `int`, `int` | `int` | bitwise XOR | +| `inot` | `int` | `int` | bitwise NOT | +| `ishl`( \* ) | `int`, `int` | `int` | shift first input left by k bits where k is unsigned interpretation of second input (leftmost bits dropped, rightmost bits set to zero) | +| `ishr`( \* ) | `int`, `int` | `int` | shift first input right by k bits where k is unsigned interpretation of second input (rightmost bits dropped, leftmost bits set to zero) | +| `irotl`( \* ) | `int`, `int` | `int` | rotate first input left by k bits where k is unsigned interpretation of second input (leftmost bits replace rightmost bits) | +| `irotr`( \* ) | `int`, `int` | `int` | rotate first input right by k bits where k is unsigned interpretation of second input (rightmost bits replace leftmost bits) | +| `itostring_u` | `int` | `string` | decimal string representation of unsigned integer | +| `itostring_s` | `int` | `string` | decimal string representation of signed integer | + #### `arithmetic.float.types` diff --git a/specification/schema/hugr_schema_live.json b/specification/schema/hugr_schema_live.json index de354b052..0b8096a43 100644 --- a/specification/schema/hugr_schema_live.json +++ b/specification/schema/hugr_schema_live.json @@ -1084,8 +1084,7 @@ "required": [ "extension", "name", - "description", - "lower_funcs" + "description" ], "title": "OpDef", "type": "object" diff --git a/specification/schema/hugr_schema_strict_live.json b/specification/schema/hugr_schema_strict_live.json index 105d5db8c..ba23a6233 100644 --- a/specification/schema/hugr_schema_strict_live.json +++ b/specification/schema/hugr_schema_strict_live.json @@ -1084,8 +1084,7 @@ "required": [ "extension", "name", - "description", - "lower_funcs" + "description" ], "title": "OpDef", "type": "object" diff --git a/specification/schema/testing_hugr_schema_live.json b/specification/schema/testing_hugr_schema_live.json index 27bfbfb57..b58866307 100644 --- a/specification/schema/testing_hugr_schema_live.json +++ b/specification/schema/testing_hugr_schema_live.json @@ -1084,8 +1084,7 @@ "required": [ "extension", "name", - "description", - "lower_funcs" + "description" ], "title": "OpDef", "type": "object" diff --git a/specification/schema/testing_hugr_schema_strict_live.json b/specification/schema/testing_hugr_schema_strict_live.json index 4dcac4039..ffa2b42f4 100644 --- a/specification/schema/testing_hugr_schema_strict_live.json +++ b/specification/schema/testing_hugr_schema_strict_live.json @@ -1084,8 +1084,7 @@ "required": [ "extension", "name", - "description", - "lower_funcs" + "description" ], "title": "OpDef", "type": "object" diff --git a/specification/std_extensions/arithmetic/int.json b/specification/std_extensions/arithmetic/int.json index 944a57e5f..6eb546736 100644 --- a/specification/std_extensions/arithmetic/int.json +++ b/specification/std_extensions/arithmetic/int.json @@ -204,10 +204,6 @@ "description": "as idivmod_checked_s but discarding the second output", "signature": { "params": [ - { - "tp": "BoundedNat", - "bound": 7 - }, { "tp": "BoundedNat", "bound": 7 @@ -238,7 +234,7 @@ "args": [ { "tya": "Variable", - "idx": 1, + "idx": 0, "cached_decl": { "tp": "BoundedNat", "bound": 7 @@ -294,10 +290,6 @@ "description": "as idivmod_checked_u but discarding the second output", "signature": { "params": [ - { - "tp": "BoundedNat", - "bound": 7 - }, { "tp": "BoundedNat", "bound": 7 @@ -328,7 +320,7 @@ "args": [ { "tya": "Variable", - "idx": 1, + "idx": 0, "cached_decl": { "tp": "BoundedNat", "bound": 7 @@ -384,10 +376,6 @@ "description": "as idivmod_s but discarding the second output", "signature": { "params": [ - { - "tp": "BoundedNat", - "bound": 7 - }, { "tp": "BoundedNat", "bound": 7 @@ -418,7 +406,7 @@ "args": [ { "tya": "Variable", - "idx": 1, + "idx": 0, "cached_decl": { "tp": "BoundedNat", "bound": 7 @@ -457,10 +445,6 @@ "description": "as idivmod_u but discarding the second output", "signature": { "params": [ - { - "tp": "BoundedNat", - "bound": 7 - }, { "tp": "BoundedNat", "bound": 7 @@ -491,7 +475,7 @@ "args": [ { "tya": "Variable", - "idx": 1, + "idx": 0, "cached_decl": { "tp": "BoundedNat", "bound": 7 @@ -527,13 +511,9 @@ "idivmod_checked_s": { "extension": "arithmetic.int", "name": "idivmod_checked_s", - "description": "given signed integer -2^{N-1} <= n < 2^{N-1} and unsigned 0 <= m < 2^M, generates signed q and unsigned r where q*m+r=n, 0<=r