(&self, context: Context, arguments_types: Vec<Type>)
| 58 | #[typetag::serde] |
| 59 | impl CustomOperationBody for GoldschmidtDivision { |
| 60 | fn instantiate(&self, context: Context, arguments_types: Vec<Type>) -> Result<Graph> { |
| 61 | if arguments_types.len() != 2 && arguments_types.len() != 3 { |
| 62 | return Err(runtime_error!( |
| 63 | "Invalid number of arguments for GoldschmidtDivision, given {}, expected 2 or 3", |
| 64 | arguments_types.len() |
| 65 | )); |
| 66 | } |
| 67 | |
| 68 | let dividend_type = arguments_types[0].clone(); |
| 69 | let divisor_type = arguments_types[1].clone(); |
| 70 | if dividend_type.get_scalar_type() != divisor_type.get_scalar_type() { |
| 71 | return Err(runtime_error!( |
| 72 | "Invalid scalar types for GoldschmidtDivision: dividend scalr type {} and divisor scalar type {} must be the same", |
| 73 | dividend_type.get_scalar_type(), |
| 74 | divisor_type.get_scalar_type() |
| 75 | )); |
| 76 | } |
| 77 | if !divisor_type.is_scalar() && !divisor_type.is_array() { |
| 78 | return Err(runtime_error!( |
| 79 | "Divisor in GoldschmidtDivision must be a scalar or an array" |
| 80 | )); |
| 81 | } |
| 82 | if !dividend_type.is_scalar() && !dividend_type.is_array() { |
| 83 | return Err(runtime_error!( |
| 84 | "Dividend in GoldschmidtDivision must be a scalar or an array" |
| 85 | )); |
| 86 | } |
| 87 | |
| 88 | let sc = dividend_type.get_scalar_type(); |
| 89 | if sc.size_in_bits() < 64 { |
| 90 | return Err(runtime_error!( |
| 91 | "Divisor in GoldshmidtDivision supported only for 64-bit+ types: INT64, UINT64, INT128, UINT128" |
| 92 | )); |
| 93 | } |
| 94 | let has_initial_approximation = arguments_types.len() == 3; |
| 95 | if has_initial_approximation { |
| 96 | let initial_approximation_t = arguments_types[2].clone(); |
| 97 | if initial_approximation_t != divisor_type { |
| 98 | return Err(runtime_error!( |
| 99 | "Divisor and initial approximation must have the same type." |
| 100 | )); |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | let g_initial_approximation = |
| 105 | inverse_initial_approximation(&context, divisor_type.clone(), self.denominator_cap_2k)?; |
| 106 | let g = context.create_graph()?; |
| 107 | let dividend = g.input(dividend_type)?; |
| 108 | let divisor = g.input(divisor_type.clone())?; |
| 109 | let approximation = if has_initial_approximation { |
| 110 | g.input(divisor_type)? |
| 111 | } else if self.denominator_cap_2k == 0 { |
| 112 | g.ones(divisor_type)? |
| 113 | } else { |
| 114 | g.call(g_initial_approximation, vec![divisor.clone()])? |
| 115 | }; |
| 116 | // Now, we do Goldschmidt approximation for computing 1 / x, |
| 117 | // The formula for Goldschmidt division iteration is |
nothing calls this directly
no test coverage detected