Skip to content

Commit 0243267

Browse files
committed
Drop Zero Construction of PositiveF64
Replace ad-hoc `PositiveF64::new(0.0)` placeholders with Option-based patterns and a new conditional_add helper. - Add `PositiveF64::conditional_add` for adding an optional probability. - Change `compile_tern` branch weights from [PositiveF64; 2] to (PositiveF64, Option<PositiveF64>). - Switch tapleaf enumeration prob to Option<Reverse<PositiveF64>>. - Refactor `cost_1d` to use `conditional_add` instead of match branches.
1 parent 976fb33 commit 0243267

3 files changed

Lines changed: 62 additions & 36 deletions

File tree

src/policy/compiler.rs

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -497,14 +497,16 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> AstElemExt<Pk, Ctx> {
497497
/// and a probability of dissatisfaction; if `dissat_prob` is `None`
498498
/// then it is assumed that dissatisfaction never occurs
499499
fn cost_1d(&self, sat_prob: PositiveF64, dissat_prob: Option<PositiveF64>) -> PositiveF64 {
500-
PositiveF64::new(self.ms.ext.pk_cost as f64)
501-
+ PositiveF64::new(self.comp_ext_data.sat_cost) * sat_prob
502-
+ match (dissat_prob, self.comp_ext_data.dissat_cost) {
503-
(Some(prob), Some(cost)) => prob * PositiveF64::new(cost),
504-
(Some(_), None) => PositiveF64::new(f64::INFINITY),
505-
(None, Some(_)) => PositiveF64::new(0.0),
506-
(None, None) => PositiveF64::new(0.0),
507-
}
500+
let sat_cost = (self.comp_ext_data.sat_cost > 0.0)
501+
.then(|| PositiveF64::new(self.comp_ext_data.sat_cost) * sat_prob);
502+
let base = PositiveF64::new(self.ms.ext.pk_cost as f64).conditional_add(sat_cost);
503+
let dissat_cost = match (dissat_prob, self.comp_ext_data.dissat_cost) {
504+
(Some(_), Some(0.0)) => None,
505+
(Some(prob), Some(cost)) => Some(prob * PositiveF64::new(cost)),
506+
(Some(_), None) => Some(PositiveF64::INFINITY),
507+
(None, _) => None,
508+
};
509+
base.conditional_add(dissat_cost)
508510
}
509511
}
510512

@@ -785,8 +787,19 @@ where
785787
};
786788
}
787789
macro_rules! compile_tern {
788-
($a:expr, $b:expr, $c: expr, $w: expr) => {
789-
compile_tern(policy_cache, policy, &mut ret, $a, $b, $c, $w, sat_prob, dissat_prob)?
790+
($a:expr, $b:expr, $c: expr, [$ab_prob: expr, $c_prob: expr]) => {
791+
compile_tern(
792+
policy_cache,
793+
policy,
794+
&mut ret,
795+
$a,
796+
$b,
797+
$c,
798+
$ab_prob,
799+
$c_prob,
800+
sat_prob,
801+
dissat_prob,
802+
)?
790803
};
791804
}
792805

@@ -828,7 +841,6 @@ where
828841
best_compilations(policy_cache, subs[0].as_ref(), sat_prob, None)?;
829842

830843
let one = PositiveF64::new(1.0);
831-
let zero = PositiveF64::new(0.0);
832844
compile_binary!(&mut left, &mut right, [one, one], Terminal::AndB);
833845
compile_binary!(&mut right, &mut left, [one, one], Terminal::AndB);
834846
compile_binary!(&mut left, &mut right, [one, one], Terminal::AndV);
@@ -838,28 +850,27 @@ where
838850
CompilationKey::from_type(Type::FALSE, ExtData::FALSE.has_free_verify, dissat_prob),
839851
AstElemExt::terminal(Miniscript::FALSE),
840852
);
841-
compile_tern!(&mut left, &mut q_zero_right, &mut zero_comp, [one, zero]);
842-
compile_tern!(&mut right, &mut q_zero_left, &mut zero_comp, [one, zero]);
853+
compile_tern!(&mut left, &mut q_zero_right, &mut zero_comp, [one, None]);
854+
compile_tern!(&mut right, &mut q_zero_left, &mut zero_comp, [one, None]);
843855
}
844856
Concrete::Or(ref subs) => {
845857
let (lw, rw) = PositiveF64::normalized(subs[0].0, subs[1].0);
846-
let zero = PositiveF64::new(0.0);
847858

848859
//and-or
849860
if let (Concrete::And(x), _) = (subs[0].1.as_ref(), subs[1].1.as_ref()) {
850861
let mut a1 = best_compilations(
851862
policy_cache,
852863
x[0].as_ref(),
853864
lw * sat_prob,
854-
Some(dissat_prob.unwrap_or(zero) + rw * sat_prob),
865+
Some((rw * sat_prob).conditional_add(dissat_prob)),
855866
)?;
856867
let mut a2 = best_compilations(policy_cache, x[0].as_ref(), lw * sat_prob, None)?;
857868

858869
let mut b1 = best_compilations(
859870
policy_cache,
860871
x[1].as_ref(),
861872
lw * sat_prob,
862-
Some(dissat_prob.unwrap_or(zero) + rw * sat_prob),
873+
Some((rw * sat_prob).conditional_add(dissat_prob)),
863874
)?;
864875
let mut b2 = best_compilations(policy_cache, x[1].as_ref(), lw * sat_prob, None)?;
865876

@@ -870,23 +881,23 @@ where
870881
dissat_prob,
871882
)?;
872883

873-
compile_tern!(&mut a1, &mut b2, &mut c, [lw, rw]);
874-
compile_tern!(&mut b1, &mut a2, &mut c, [lw, rw]);
884+
compile_tern!(&mut a1, &mut b2, &mut c, [lw, Some(rw)]);
885+
compile_tern!(&mut b1, &mut a2, &mut c, [lw, Some(rw)]);
875886
};
876887
if let (_, Concrete::And(x)) = (&subs[0].1.as_ref(), subs[1].1.as_ref()) {
877888
let mut a1 = best_compilations(
878889
policy_cache,
879890
x[0].as_ref(),
880891
rw * sat_prob,
881-
Some(dissat_prob.unwrap_or(zero) + lw * sat_prob),
892+
Some((lw * sat_prob).conditional_add(dissat_prob)),
882893
)?;
883894
let mut a2 = best_compilations(policy_cache, x[0].as_ref(), rw * sat_prob, None)?;
884895

885896
let mut b1 = best_compilations(
886897
policy_cache,
887898
x[1].as_ref(),
888899
rw * sat_prob,
889-
Some(dissat_prob.unwrap_or(zero) + lw * sat_prob),
900+
Some((lw * sat_prob).conditional_add(dissat_prob)),
890901
)?;
891902
let mut b2 = best_compilations(policy_cache, x[1].as_ref(), rw * sat_prob, None)?;
892903

@@ -897,13 +908,13 @@ where
897908
dissat_prob,
898909
)?;
899910

900-
compile_tern!(&mut a1, &mut b2, &mut c, [rw, lw]);
901-
compile_tern!(&mut b1, &mut a2, &mut c, [rw, lw]);
911+
compile_tern!(&mut a1, &mut b2, &mut c, [rw, Some(lw)]);
912+
compile_tern!(&mut b1, &mut a2, &mut c, [rw, Some(lw)]);
902913
};
903914

904915
let dissat_probs = |w: PositiveF64| -> Vec<Option<PositiveF64>> {
905916
vec![
906-
Some(dissat_prob.unwrap_or(zero) + w * sat_prob),
917+
Some((w * sat_prob).conditional_add(dissat_prob)),
907918
Some(w * sat_prob),
908919
dissat_prob,
909920
None,
@@ -953,11 +964,15 @@ where
953964
let k = thresh.k();
954965
let n = thresh.n();
955966

956-
let (sat_ratio, dissat_ratio) = PositiveF64::normalized(
957-
PositiveF64::new(k as f64),
958-
PositiveF64::new((n - k) as f64),
959-
);
960-
let zero = PositiveF64::new(0.0);
967+
let (sat_ratio, dissat_ratio) = if n > k {
968+
let (s, d) = PositiveF64::normalized(
969+
PositiveF64::new(k as f64),
970+
PositiveF64::new((n - k) as f64),
971+
);
972+
(s, Some(d))
973+
} else {
974+
(PositiveF64::new(1.0), None)
975+
};
961976

962977
let mut sub_ext_data = Vec::with_capacity(n);
963978

@@ -968,7 +983,9 @@ where
968983
for (i, ast) in thresh.iter().enumerate() {
969984
let sp = sat_prob * sat_ratio;
970985
//Expressions must be dissatisfiable
971-
let dp = Some(dissat_prob.unwrap_or(zero) + dissat_ratio * sat_prob);
986+
let dp = dissat_ratio
987+
.map(|ratio| (ratio * sat_prob).conditional_add(dissat_prob))
988+
.or(dissat_prob);
972989
let be = best(types::Base::B, policy_cache, ast.as_ref(), sp, dp)?;
973990
let bw = best(types::Base::W, policy_cache, ast.as_ref(), sp, dp)?;
974991

@@ -1111,20 +1128,23 @@ fn compile_tern<Pk: MiniscriptKey, Ctx: ScriptContext>(
11111128
a_comp: &mut BTreeMap<CompilationKey, AstElemExt<Pk, Ctx>>,
11121129
b_comp: &mut BTreeMap<CompilationKey, AstElemExt<Pk, Ctx>>,
11131130
c_comp: &mut BTreeMap<CompilationKey, AstElemExt<Pk, Ctx>>,
1114-
weights: [PositiveF64; 2],
1131+
ab_branch_prob: PositiveF64,
1132+
c_branch_prob: Option<PositiveF64>,
11151133
sat_prob: PositiveF64,
11161134
dissat_prob: Option<PositiveF64>,
11171135
) -> Result<(), CompilerError> {
1136+
let ab_prob = ab_branch_prob.value();
1137+
let c_prob = c_branch_prob.map_or(0.0, |p| p.value());
11181138
for a in a_comp.values_mut() {
11191139
let aref = Arc::clone(&a.ms);
11201140
for b in b_comp.values_mut() {
11211141
let bref = Arc::clone(&b.ms);
11221142
for c in c_comp.values_mut() {
11231143
let cref = Arc::clone(&c.ms);
11241144
let ast = Terminal::AndOr(Arc::clone(&aref), Arc::clone(&bref), Arc::clone(&cref));
1125-
a.comp_ext_data.branch_prob = Some(weights[0].value());
1126-
b.comp_ext_data.branch_prob = Some(weights[0].value());
1127-
c.comp_ext_data.branch_prob = Some(weights[1].value());
1145+
a.comp_ext_data.branch_prob = Some(ab_prob);
1146+
b.comp_ext_data.branch_prob = Some(ab_prob);
1147+
c.comp_ext_data.branch_prob = Some(c_prob);
11281148
if let Ok(new_ext) = AstElemExt::ternary(ast, a, b, c) {
11291149
insert_best_wrapped(policy_cache, policy, ret, new_ext, sat_prob, dissat_prob)?;
11301150
}

src/policy/concrete.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,7 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
568568
// Stopping condition: When NONE of the inputs can be further enumerated.
569569
'outer: loop {
570570
//--- FIND a plausible node ---
571-
let mut prob: Reverse<PositiveF64> = Reverse(PositiveF64::new(0.0));
571+
let mut prob: Option<Reverse<PositiveF64>> = None;
572572
let mut curr_policy: Arc<Self> = Arc::new(Self::Unsatisfiable);
573573
let mut curr_pol_replace_vec: Vec<(f64, Arc<Self>)> = vec![];
574574
let mut no_more_enum = false;
@@ -583,7 +583,7 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
583583

584584
if prev_len < enum_len {
585585
// Plausible node found
586-
prob = *p;
586+
prob = Some(*p);
587587
curr_policy = Arc::clone(pol);
588588
break 'inner;
589589
} else if i == tapleaf_prob_vec.len() - 1 {
@@ -610,7 +610,8 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
610610
// with children nodes
611611

612612
// Remove current node
613-
assert!(tapleaf_prob_vec.remove(&(prob, curr_policy.clone())));
613+
assert!(tapleaf_prob_vec
614+
.remove(&(prob.expect("a plausible node was found"), curr_policy.clone())));
614615
pol_prob_map.remove(&curr_policy);
615616

616617
// OPTIMIZATION - Move marked nodes into final vector

src/primitives/positive_f64.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ impl PositiveF64 {
3838
let sum = a.0 + b.0;
3939
(Self(a.0 / sum), Self(b.0 / sum))
4040
}
41+
42+
/// Adds an optional value to `self`, returning `self` unchanged if the value is
43+
/// `None`.
44+
#[must_use]
45+
pub fn conditional_add(self, other: Option<Self>) -> Self { other.map_or(self, |i| self + i) }
4146
}
4247

4348
impl TryFrom<u32> for PositiveF64 {

0 commit comments

Comments
 (0)