1
use conjure_cp::ast::Expression as Expr;
2
use conjure_cp::ast::SymbolTable;
3
use conjure_cp::rule_engine::{
4
    ApplicationError::RuleNotApplicable, ApplicationResult, Reduction, register_rule,
5
};
6

            
7
use conjure_cp::ast::AbstractLiteral::Matrix;
8
use conjure_cp::ast::Metadata;
9
use conjure_cp::ast::Moo;
10
use conjure_cp::into_matrix_expr;
11

            
12
use itertools::Itertools;
13

            
14
use super::boolean::{
15
    tseytin_and, tseytin_iff, tseytin_imply, tseytin_mux, tseytin_not, tseytin_or, tseytin_xor,
16
};
17
use super::integer_repr::{BITS, validate_sat_int_operands};
18

            
19
use conjure_cp::ast::CnfClause;
20

            
21
/// Converts an inequality expression between two SATInts to a boolean expression in cnf.
22
///
23
/// ```text
24
/// SATInt(a) </>/<=/>= SATInt(b) ~> Bool
25
///
26
/// ```
27
#[register_rule(("SAT", 4100))]
28
fn cnf_int_ineq(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
29
    let (lhs, rhs, strict) = match expr {
30
        Expr::Lt(_, x, y) => (y, x, true),
31
        Expr::Gt(_, x, y) => (x, y, true),
32
        Expr::Leq(_, x, y) => (y, x, false),
33
        Expr::Geq(_, x, y) => (x, y, false),
34
        _ => return Err(RuleNotApplicable),
35
    };
36

            
37
    let binding = validate_sat_int_operands(vec![lhs.as_ref().clone(), rhs.as_ref().clone()])?;
38
    let [lhs_bits, rhs_bits] = binding.as_slice() else {
39
        return Err(RuleNotApplicable);
40
    };
41

            
42
    let mut new_symbols = symbols.clone();
43
    let mut new_clauses = vec![];
44

            
45
    let output = inequality_boolean(
46
        lhs_bits.clone(),
47
        rhs_bits.clone(),
48
        strict,
49
        &mut new_clauses,
50
        &mut new_symbols,
51
    );
52
    Ok(Reduction::cnf(output, new_clauses, new_symbols))
53
}
54

            
55
/// Converts a = expression between two SATInts to a boolean expression in cnf
56
///
57
/// ```text
58
/// SATInt(a) = SATInt(b) ~> Bool
59
///
60
/// ```
61
#[register_rule(("SAT", 9100))]
62
fn cnf_int_eq(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
63
    let Expr::Eq(_, lhs, rhs) = expr else {
64
        return Err(RuleNotApplicable);
65
    };
66

            
67
    let binding = validate_sat_int_operands(vec![lhs.as_ref().clone(), rhs.as_ref().clone()])?;
68
    let [lhs_bits, rhs_bits] = binding.as_slice() else {
69
        return Err(RuleNotApplicable);
70
    };
71

            
72
    let mut output = true.into();
73
    let mut new_symbols = symbols.clone();
74
    let mut new_clauses = vec![];
75
    let mut comparison;
76

            
77
    for i in 0..BITS {
78
        comparison = tseytin_iff(
79
            lhs_bits[i].clone(),
80
            rhs_bits[i].clone(),
81
            &mut new_clauses,
82
            &mut new_symbols,
83
        );
84
        output = tseytin_and(
85
            &vec![comparison, output],
86
            &mut new_clauses,
87
            &mut new_symbols,
88
        );
89
    }
90

            
91
    Ok(Reduction::cnf(output, new_clauses, new_symbols))
92
}
93

            
94
/// Converts a != expression between two SATInts to a boolean expression in cnf
95
///
96
/// ```text
97
/// SATInt(a) != SATInt(b) ~> Bool
98
///
99
/// ```
100
#[register_rule(("SAT", 4100))]
101
fn cnf_int_neq(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
102
    let Expr::Neq(_, lhs, rhs) = expr else {
103
        return Err(RuleNotApplicable);
104
    };
105

            
106
    let binding = validate_sat_int_operands(vec![lhs.as_ref().clone(), rhs.as_ref().clone()])?;
107
    let [lhs_bits, rhs_bits] = binding.as_slice() else {
108
        return Err(RuleNotApplicable);
109
    };
110

            
111
    let mut output = false.into();
112
    let mut new_symbols = symbols.clone();
113
    let mut new_clauses = vec![];
114
    let mut comparison;
115

            
116
    for i in 0..BITS {
117
        comparison = tseytin_xor(
118
            lhs_bits[i].clone(),
119
            rhs_bits[i].clone(),
120
            &mut new_clauses,
121
            &mut new_symbols,
122
        );
123
        output = tseytin_or(
124
            &vec![comparison, output],
125
            &mut new_clauses,
126
            &mut new_symbols,
127
        );
128
    }
129

            
130
    Ok(Reduction::cnf(output, new_clauses, new_symbols))
131
}
132

            
133
// Creates a boolean expression for > or >=
134
// a > b or a >= b
135
// This can also be used for < and <= by reversing the order of the inputs
136
// Returns result, new symbol table, new clauses
137
fn inequality_boolean(
138
    a: Vec<Expr>,
139
    b: Vec<Expr>,
140
    strict: bool,
141
    clauses: &mut Vec<CnfClause>,
142
    symbols: &mut SymbolTable,
143
) -> Expr {
144
    let mut notb;
145
    let mut output;
146

            
147
    if strict {
148
        notb = tseytin_not(b[0].clone(), clauses, symbols);
149
        output = tseytin_and(&vec![a[0].clone(), notb], clauses, symbols);
150
    } else {
151
        output = tseytin_imply(b[0].clone(), a[0].clone(), clauses, symbols);
152
    }
153

            
154
    //TODO: There may be room for simplification, and constant optimization
155

            
156
    let mut lhs;
157
    let mut rhs;
158
    let mut iff;
159
    for n in 1..(BITS - 1) {
160
        notb = tseytin_not(b[n].clone(), clauses, symbols);
161
        lhs = tseytin_and(&vec![a[n].clone(), notb.clone()], clauses, symbols);
162
        iff = tseytin_iff(a[n].clone(), b[n].clone(), clauses, symbols);
163
        rhs = tseytin_and(&vec![iff.clone(), output.clone()], clauses, symbols);
164
        output = tseytin_or(&vec![lhs.clone(), rhs.clone()], clauses, symbols);
165
    }
166

            
167
    // final bool is the sign bit and should be handled inversely
168
    let nota = tseytin_not(a[BITS - 1].clone(), clauses, symbols);
169
    lhs = tseytin_and(&vec![nota, b[BITS - 1].clone()], clauses, symbols);
170
    iff = tseytin_iff(a[BITS - 1].clone(), b[BITS - 1].clone(), clauses, symbols);
171
    rhs = tseytin_and(&vec![iff, output.clone()], clauses, symbols);
172
    output = tseytin_or(&vec![lhs, rhs], clauses, symbols);
173

            
174
    output
175
}
176

            
177
/// Converts sum of SATInts to a single SATInt
178
///
179
/// ```text
180
/// Sum(SATInt(a), SATInt(b), ...) ~> SATInt(c)
181
///
182
/// ```
183
#[register_rule(("SAT", 4100))]
184
fn cnf_int_sum(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
185
    let Expr::Sum(_, exprs) = expr else {
186
        return Err(RuleNotApplicable);
187
    };
188

            
189
    let Expr::AbstractLiteral(_, Matrix(exprs_list, _)) = exprs.as_ref() else {
190
        return Err(RuleNotApplicable);
191
    };
192

            
193
    let mut exprs_bits = validate_sat_int_operands(exprs_list.clone())?;
194

            
195
    let mut new_symbols = symbols.clone();
196
    let mut values;
197
    let mut new_clauses = vec![];
198

            
199
    while exprs_bits.len() > 1 {
200
        let mut next = Vec::with_capacity(exprs_bits.len().div_ceil(2));
201
        let mut iter = exprs_bits.into_iter();
202

            
203
        while let Some(a) = iter.next() {
204
            if let Some(b) = iter.next() {
205
                values = tseytin_int_adder(&a, &b, BITS, &mut new_clauses, &mut new_symbols);
206
                next.push(values);
207
            } else {
208
                next.push(a);
209
            }
210
        }
211

            
212
        exprs_bits = next;
213
    }
214

            
215
    let result = exprs_bits.pop().unwrap();
216

            
217
    Ok(Reduction::cnf(
218
        Expr::SATInt(Metadata::new(), Moo::new(into_matrix_expr!(result))),
219
        new_clauses,
220
        new_symbols,
221
    ))
222
}
223

            
224
// Returns result, new symbol table, new clauses
225
fn tseytin_int_adder(
226
    x: &[Expr],
227
    y: &[Expr],
228
    bits: usize,
229
    clauses: &mut Vec<CnfClause>,
230
    symbols: &mut SymbolTable,
231
) -> Vec<Expr> {
232
    //TODO Optimizing for constants
233
    let (mut result, mut carry) = tseytin_half_adder(x[0].clone(), y[0].clone(), clauses, symbols);
234

            
235
    let mut output = vec![result];
236
    for i in 1..bits {
237
        (result, carry) =
238
            tseytin_full_adder(x[i].clone(), y[i].clone(), carry.clone(), clauses, symbols);
239
        output.push(result);
240
    }
241

            
242
    output
243
}
244

            
245
// Returns: result, carry, new symbol table, new clauses
246
fn tseytin_full_adder(
247
    a: Expr,
248
    b: Expr,
249
    carry: Expr,
250
    clauses: &mut Vec<CnfClause>,
251
    symbols: &mut SymbolTable,
252
) -> (Expr, Expr) {
253
    let axorb = tseytin_xor(a.clone(), b.clone(), clauses, symbols);
254
    let result = tseytin_xor(axorb.clone(), carry.clone(), clauses, symbols);
255
    let aandb = tseytin_and(&vec![a, b], clauses, symbols);
256
    let carryandaxorb = tseytin_and(&vec![carry, axorb], clauses, symbols);
257
    let carryout = tseytin_or(&vec![aandb, carryandaxorb], clauses, symbols);
258

            
259
    (result, carryout)
260
}
261

            
262
fn tseytin_half_adder(
263
    a: Expr,
264
    b: Expr,
265
    clauses: &mut Vec<CnfClause>,
266
    symbols: &mut SymbolTable,
267
) -> (Expr, Expr) {
268
    let result = tseytin_xor(a.clone(), b.clone(), clauses, symbols);
269
    let carry = tseytin_and(&vec![a, b], clauses, symbols);
270

            
271
    (result, carry)
272
}
273

            
274
/// this function is for specifically adding a power of two constant to a cnf int
275
fn tseytin_add_two_power(
276
    expr: &[Expr],
277
    exponent: usize,
278
    bits: usize,
279
    clauses: &mut Vec<CnfClause>,
280
    symbols: &mut SymbolTable,
281
) -> Vec<Expr> {
282
    let mut result = vec![];
283
    let mut product = expr[exponent].clone();
284

            
285
    for item in expr.iter().take(exponent) {
286
        result.push(item.clone());
287
    }
288

            
289
    result.push(tseytin_not(expr[exponent].clone(), clauses, symbols));
290

            
291
    for item in expr.iter().take(bits).skip(exponent + 1) {
292
        result.push(tseytin_xor(product.clone(), item.clone(), clauses, symbols));
293
        product = tseytin_and(&vec![product, item.clone()], clauses, symbols);
294
    }
295

            
296
    result
297
}
298

            
299
// Returns result, new symbol table, new clauses
300
fn cnf_shift_add_multiply(
301
    x: &[Expr],
302
    y: &[Expr],
303
    bits: usize,
304
    clauses: &mut Vec<CnfClause>,
305
    symbols: &mut SymbolTable,
306
) -> Vec<Expr> {
307
    let mut x = x.to_owned();
308
    let mut y = y.to_owned();
309

            
310
    //TODO Optimizing for constants
311
    //TODO Optimize addition for i left shifted values - skip first i bits
312

            
313
    // extend sign bits of operands to 2*`bits`
314
    x.extend(std::iter::repeat_n(x[bits - 1].clone(), bits));
315
    y.extend(std::iter::repeat_n(y[bits - 1].clone(), bits));
316

            
317
    let mut s: Vec<Expr> = vec![];
318
    let mut x_0andy_i;
319

            
320
    for bit in &y {
321
        x_0andy_i = tseytin_and(&vec![x[0].clone(), bit.clone()], clauses, symbols);
322
        s.push(x_0andy_i);
323
    }
324

            
325
    let mut sum;
326
    let mut if_true;
327
    let mut not_x_n;
328
    let mut if_false;
329

            
330
    for item in x.iter().take(bits).skip(1) {
331
        // y << 1
332
        for i in (1..bits * 2).rev() {
333
            y[i] = y[i - 1].clone();
334
        }
335
        y[0] = false.into();
336

            
337
        // TODO switch to multiplexer
338
        sum = tseytin_int_adder(&s, &y, bits * 2, clauses, symbols);
339
        not_x_n = tseytin_not(item.clone(), clauses, symbols);
340

            
341
        for i in 0..(bits * 2) {
342
            if_true = tseytin_and(&vec![item.clone(), sum[i].clone()], clauses, symbols);
343
            if_false = tseytin_and(&vec![not_x_n.clone(), s[i].clone()], clauses, symbols);
344
            s[i] = tseytin_or(&vec![if_true.clone(), if_false.clone()], clauses, symbols);
345
        }
346
    }
347

            
348
    //TODO: At the moment, this doesn't account for overflows (perhaps this could use a bubble in the future?)
349
    s[..bits].to_vec()
350
}
351

            
352
/// Converts product of SATInts to a single SATInt
353
///
354
/// ```text
355
/// Product(SATInt(a), SATInt(b), ...) ~> SATInt(c)
356
///
357
/// ```
358
#[register_rule(("SAT", 9000))]
359
fn cnf_int_product(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
360
    let Expr::Product(_, exprs) = expr else {
361
        return Err(RuleNotApplicable);
362
    };
363

            
364
    let Expr::AbstractLiteral(_, Matrix(exprs_list, _)) = exprs.as_ref() else {
365
        return Err(RuleNotApplicable);
366
    };
367

            
368
    let mut exprs_bits = validate_sat_int_operands(exprs_list.clone())?;
369

            
370
    let mut new_symbols = symbols.clone();
371
    let mut values;
372
    let mut new_clauses = vec![];
373

            
374
    while exprs_bits.len() > 1 {
375
        let mut next = Vec::with_capacity(exprs_bits.len().div_ceil(2));
376
        let mut iter = exprs_bits.into_iter();
377

            
378
        while let Some(a) = iter.next() {
379
            if let Some(b) = iter.next() {
380
                values = cnf_shift_add_multiply(&a, &b, 8, &mut new_clauses, &mut new_symbols);
381
                next.push(values);
382
            } else {
383
                next.push(a);
384
            }
385
        }
386

            
387
        exprs_bits = next;
388
    }
389

            
390
    let result = exprs_bits.pop().unwrap();
391

            
392
    Ok(Reduction::cnf(
393
        Expr::SATInt(Metadata::new(), Moo::new(into_matrix_expr!(result))),
394
        new_clauses,
395
        new_symbols,
396
    ))
397
}
398

            
399
/// Converts negation of a SATInt to a SATInt
400
///
401
/// ```text
402
/// -SATInt(a) ~> SATInt(b)
403
///
404
/// ```
405
#[register_rule(("SAT", 4100))]
406
fn cnf_int_neg(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
407
    let Expr::Neg(_, expr) = expr else {
408
        return Err(RuleNotApplicable);
409
    };
410

            
411
    let binding = validate_sat_int_operands(vec![expr.as_ref().clone()])?;
412
    let [bits] = binding.as_slice() else {
413
        return Err(RuleNotApplicable);
414
    };
415
    let mut new_clauses = vec![];
416
    let mut new_symbols = symbols.clone();
417

            
418
    let result = tseytin_negate(bits, BITS, &mut new_clauses, &mut new_symbols);
419

            
420
    Ok(Reduction::cnf(
421
        Expr::SATInt(Metadata::new(), Moo::new(into_matrix_expr!(result))),
422
        new_clauses,
423
        new_symbols,
424
    ))
425
}
426

            
427
fn tseytin_negate(
428
    expr: &Vec<Expr>,
429
    bits: usize,
430
    clauses: &mut Vec<CnfClause>,
431
    symbols: &mut SymbolTable,
432
) -> Vec<Expr> {
433
    let mut result = vec![];
434
    // invert bits
435
    for bit in expr {
436
        result.push(tseytin_not(bit.clone(), clauses, symbols));
437
    }
438

            
439
    // add one
440
    result = tseytin_add_two_power(&result, 0, bits, clauses, symbols);
441

            
442
    result
443
}
444

            
445
/// Converts min of SATInts to a single SATInt
446
///
447
/// ```text
448
/// Min(SATInt(a), SATInt(b), ...) ~> SATInt(c)
449
///
450
/// ```
451
#[register_rule(("SAT", 4100))]
452
fn cnf_int_min(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
453
    let Expr::Min(_, exprs) = expr else {
454
        return Err(RuleNotApplicable);
455
    };
456

            
457
    let Expr::AbstractLiteral(_, Matrix(exprs_list, _)) = exprs.as_ref() else {
458
        return Err(RuleNotApplicable);
459
    };
460

            
461
    let mut exprs_bits = validate_sat_int_operands(exprs_list.clone())?;
462

            
463
    let mut new_symbols = symbols.clone();
464
    let mut values;
465
    let mut new_clauses = vec![];
466

            
467
    while exprs_bits.len() > 1 {
468
        let mut next = Vec::with_capacity(exprs_bits.len().div_ceil(2));
469
        let mut iter = exprs_bits.into_iter();
470

            
471
        while let Some(a) = iter.next() {
472
            if let Some(b) = iter.next() {
473
                values = tseytin_binary_min_max(&a, &b, true, &mut new_clauses, &mut new_symbols);
474
                next.push(values);
475
            } else {
476
                next.push(a);
477
            }
478
        }
479

            
480
        exprs_bits = next;
481
    }
482

            
483
    let result = exprs_bits.pop().unwrap();
484

            
485
    Ok(Reduction::cnf(
486
        Expr::SATInt(Metadata::new(), Moo::new(into_matrix_expr!(result))),
487
        new_clauses,
488
        new_symbols,
489
    ))
490
}
491

            
492
fn tseytin_binary_min_max(
493
    x: &[Expr],
494
    y: &[Expr],
495
    min: bool,
496
    clauses: &mut Vec<CnfClause>,
497
    symbols: &mut SymbolTable,
498
) -> Vec<Expr> {
499
    let mut out = vec![];
500

            
501
    for i in 0..BITS {
502
        out.push(tseytin_xor(x[i].clone(), y[i].clone(), clauses, symbols))
503
    }
504

            
505
    // TODO: compare generated expression to using MUX
506

            
507
    let mask = if min {
508
        // mask is 1 if x > y
509
        inequality_boolean(x.to_owned(), y.to_owned(), true, clauses, symbols)
510
    } else {
511
        // flip the args if getting maximum x < y -> 1
512
        inequality_boolean(y.to_owned(), x.to_owned(), true, clauses, symbols)
513
    };
514

            
515
    for item in out.iter_mut().take(BITS) {
516
        *item = tseytin_and(&vec![item.clone(), mask.clone()], clauses, symbols);
517
    }
518

            
519
    for i in 0..BITS {
520
        out[i] = tseytin_xor(x[i].clone(), out[i].clone(), clauses, symbols);
521
    }
522

            
523
    out
524
}
525

            
526
/// Converts max of SATInts to a single SATInt
527
///
528
/// ```text
529
/// Max(SATInt(a), SATInt(b), ...) ~> SATInt(c)
530
///
531
/// ```
532
#[register_rule(("SAT", 4100))]
533
fn cnf_int_max(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
534
    let Expr::Max(_, exprs) = expr else {
535
        return Err(RuleNotApplicable);
536
    };
537

            
538
    let Expr::AbstractLiteral(_, Matrix(exprs_list, _)) = exprs.as_ref() else {
539
        return Err(RuleNotApplicable);
540
    };
541

            
542
    let mut exprs_bits = validate_sat_int_operands(exprs_list.clone())?;
543

            
544
    let mut new_symbols = symbols.clone();
545
    let mut values;
546
    let mut new_clauses = vec![];
547

            
548
    while exprs_bits.len() > 1 {
549
        let mut next = Vec::with_capacity(exprs_bits.len().div_ceil(2));
550
        let mut iter = exprs_bits.into_iter();
551

            
552
        while let Some(a) = iter.next() {
553
            if let Some(b) = iter.next() {
554
                values = tseytin_binary_min_max(&a, &b, false, &mut new_clauses, &mut new_symbols);
555
                next.push(values);
556
            } else {
557
                next.push(a);
558
            }
559
        }
560

            
561
        exprs_bits = next;
562
    }
563

            
564
    let result = exprs_bits.pop().unwrap();
565

            
566
    Ok(Reduction::cnf(
567
        Expr::SATInt(Metadata::new(), Moo::new(into_matrix_expr!(result))),
568
        new_clauses,
569
        new_symbols,
570
    ))
571
}
572

            
573
/// Converts Abs of a SATInt to a SATInt
574
///
575
/// ```text
576
/// |SATInt(a)| ~> SATInt(b)
577
///
578
/// ```
579
#[register_rule(("SAT", 4100))]
580
fn cnf_int_abs(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
581
    let Expr::Abs(_, expr) = expr else {
582
        return Err(RuleNotApplicable);
583
    };
584

            
585
    let binding = validate_sat_int_operands(vec![expr.as_ref().clone()])?;
586
    let [bits] = binding.as_slice() else {
587
        return Err(RuleNotApplicable);
588
    };
589
    let mut new_clauses = vec![];
590
    let mut new_symbols = symbols.clone();
591

            
592
    let mut result = vec![];
593

            
594
    // invert bits
595
    for bit in bits {
596
        result.push(tseytin_not(bit.clone(), &mut new_clauses, &mut new_symbols));
597
    }
598

            
599
    // add one
600
    result = tseytin_add_two_power(&result, 0, BITS, &mut new_clauses, &mut new_symbols);
601

            
602
    for i in 0..BITS {
603
        result[i] = tseytin_mux(
604
            bits[BITS - 1].clone(),
605
            bits[i].clone(),
606
            result[i].clone(),
607
            &mut new_clauses,
608
            &mut new_symbols,
609
        )
610
    }
611

            
612
    Ok(Reduction::cnf(
613
        Expr::SATInt(Metadata::new(), Moo::new(into_matrix_expr!(result))),
614
        new_clauses,
615
        new_symbols,
616
    ))
617
}
618

            
619
/// Converts SafeDiv of SATInts to a single SATInt
620
///
621
/// ```text
622
/// SafeDiv(SATInt(a), SATInt(b)) ~> SATInt(c)
623
///
624
/// ```
625
#[register_rule(("SAT", 4100))]
626
fn cnf_int_safediv(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
627
    // Using "Restoring division" algorithm
628
    // https://en.wikipedia.org/wiki/Division_algorithm#Restoring_division
629
    let Expr::SafeDiv(_, numer, denom) = expr else {
630
        return Err(RuleNotApplicable);
631
    };
632

            
633
    let binding = validate_sat_int_operands(vec![numer.as_ref().clone(), denom.as_ref().clone()])?;
634
    let [numer_bits, denom_bits] = binding.as_slice() else {
635
        return Err(RuleNotApplicable);
636
    };
637

            
638
    // TODO: Separate into division/mod function
639
    // TODO: Support negatives
640

            
641
    let mut new_symbols = symbols.clone();
642
    let mut new_clauses = vec![];
643
    let mut quotient = vec![false.into(); BITS];
644

            
645
    let mut r = numer_bits.clone();
646
    r.extend(std::iter::repeat_n(r[BITS - 1].clone(), BITS));
647
    let mut d = std::iter::repeat_n(false.into(), BITS).collect_vec();
648
    d.extend(denom_bits.clone());
649

            
650
    let minus_d = tseytin_negate(&d.clone(), 2 * BITS, &mut new_clauses, &mut new_symbols);
651
    let mut rminusd;
652

            
653
    for i in (0..BITS).rev() {
654
        // r << 1
655
        for j in (1..BITS * 2).rev() {
656
            r[j] = r[j - 1].clone();
657
        }
658
        r[0] = false.into();
659

            
660
        rminusd = tseytin_int_adder(
661
            &r.clone(),
662
            &minus_d.clone(),
663
            2 * BITS,
664
            &mut new_clauses,
665
            &mut new_symbols,
666
        );
667

            
668
        // TODO: For mod don't calculate on final iter
669
        quotient[i] = tseytin_not(
670
            // q[i] = inverse of sign bit - 1 if positive, 0 if negative
671
            rminusd[2 * BITS - 1].clone(),
672
            &mut new_clauses,
673
            &mut new_symbols,
674
        );
675

            
676
        // TODO: For div don't calculate on final iter
677
        for j in 0..(2 * BITS) {
678
            r[j] = tseytin_mux(
679
                quotient[i].clone(),
680
                r[j].clone(),       // use r if negative
681
                rminusd[j].clone(), // use r-d if positive
682
                &mut new_clauses,
683
                &mut new_symbols,
684
            );
685
        }
686
    }
687

            
688
    Ok(Reduction::cnf(
689
        Expr::SATInt(Metadata::new(), Moo::new(into_matrix_expr!(quotient))),
690
        new_clauses,
691
        new_symbols,
692
    ))
693
}
694

            
695
/*
696
/// Converts SafeMod of SATInts to a single SATInt
697
///
698
/// ```text
699
/// SafeMod(SATInt(a), SATInt(b)) ~> SATInt(c)
700
///
701
/// ```
702
#[register_rule(("SAT", 4100))]
703
fn cnf_int_safemod(expr: &Expr, _: &SymbolTable) -> ApplicationResult {}
704

            
705
/// Converts SafePow of SATInts to a single SATInt
706
///
707
/// ```text
708
/// SafePow(SATInt(a), SATInt(b)) ~> SATInt(c)
709
///
710
/// ```
711
#[register_rule(("SAT", 4100))]
712
fn cnf_int_safepow(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
713
    // use 'Exponentiation by squaring'
714
}
715
*/