Skip to content

Commit 7fd88d7

Browse files
committed
Add very suspicious imod unop
1 parent a0bb36c commit 7fd88d7

10 files changed

Lines changed: 64 additions & 9 deletions

File tree

crates/autodiff/src/lib.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,18 @@ impl Autodiff<'_> {
177177
self.pack(var, x, dx)
178178
}
179179
&Expr::Unary { op, arg } => match op {
180-
// boring case
180+
// boring cases
181181
Unop::Not => self.code.push(Instr {
182182
var,
183183
expr: Expr::Unary { op: Unop::Not, arg },
184184
}),
185+
Unop::IMod => self.code.push(Instr {
186+
var,
187+
expr: Expr::Unary {
188+
op: Unop::IMod,
189+
arg,
190+
},
191+
}),
185192

186193
// interesting cases
187194
Unop::Neg => {

crates/core/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ pub enum Unop {
192192
// `Bool` -> `Bool`
193193
Not,
194194

195+
// `Fin` -> `Fin`
196+
IMod,
197+
195198
// `F64` -> `F64`
196199
Neg,
197200
Abs,

crates/interp/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,14 @@ impl<'a, 'b, O: Opaque, T: Refs<'a, Opaque = O>> Interpreter<'a, 'b, O, T> {
218218
match op {
219219
Unop::Not => Val::Bool(!x.bool()),
220220

221+
Unop::IMod => {
222+
let n = match self.typemap[self.types[self.def.vars[arg.var()].ty()].ty()] {
223+
Ty::Fin { size } => size,
224+
_ => unreachable!(),
225+
};
226+
Val::Fin(x.fin() % n)
227+
}
228+
221229
Unop::Neg => val_f64(-x.f64()),
222230
Unop::Abs => val_f64(x.f64().abs()),
223231
Unop::Sign => val_f64(x.f64().signum()),

crates/transpose/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,7 @@ impl<'a> Transpose<'a> {
572572
match self.f.vars[var.var()] {
573573
DUAL => match op {
574574
Unop::Not
575+
| Unop::IMod
575576
| Unop::Abs
576577
| Unop::Sign
577578
| Unop::Ceil
@@ -601,7 +602,7 @@ impl<'a> Transpose<'a> {
601602
},
602603
_ => {
603604
let x = match op {
604-
Unop::Not => arg,
605+
Unop::Not | Unop::IMod => arg,
605606
Unop::Neg
606607
| Unop::Abs
607608
| Unop::Sign

crates/wasm/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,15 @@ impl<'a, 'b, O: Eq + Hash, T: Refs<'a, Opaque = O>> Codegen<'a, 'b, O, T> {
737737
self.get(arg);
738738
self.wasm.instruction(&Instruction::I32Eqz);
739739
}
740+
Unop::IMod => {
741+
let n = match self.def.types[self.def.vars[instr.var.var()].ty()] {
742+
Ty::Fin { size } => size,
743+
_ => unreachable!(),
744+
};
745+
self.get(arg);
746+
self.wasm.instruction(&Instruction::I32Const(n as i32));
747+
self.wasm.instruction(&Instruction::I32RemU);
748+
}
740749
Unop::Neg => {
741750
self.get(arg);
742751
self.wasm.instruction(&Instruction::F64Neg);

crates/web/src/lib.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -947,12 +947,10 @@ impl FuncBuilder {
947947
pub fn num(&mut self, t: usize, x: f64) -> Result<usize, JsError> {
948948
match self.ty(t)? {
949949
Ty::F64 | Ty::T64 => Ok(self.constant(t, rose::Expr::F64 { val: x })),
950-
&Ty::Fin { size } => {
950+
&Ty::Fin { .. } => {
951951
let y = x as usize;
952952
if y as f64 != x {
953953
Err(JsError::new("can't be represented by an unsigned integer"))
954-
} else if y >= size {
955-
Err(JsError::new("out of range"))
956954
} else {
957955
Ok(self.constant(t, rose::Expr::Fin { val: y }))
958956
}
@@ -1194,6 +1192,17 @@ impl Block {
11941192
self.instr(f, t, expr)
11951193
}
11961194

1195+
/// Return the variable ID for a new index modulus instruction on `arg`.
1196+
///
1197+
/// Assumes `arg` is defined, in scope, and has boolean type.
1198+
pub fn imod(&mut self, f: &mut FuncBuilder, t: usize, arg: usize) -> usize {
1199+
let expr = rose::Expr::Unary {
1200+
op: rose::Unop::IMod,
1201+
arg: id::var(arg),
1202+
};
1203+
self.instr(f, id::ty(t), expr)
1204+
}
1205+
11971206
/// Return the variable ID for a new absolute value instruction on `arg`.
11981207
///
11991208
/// Assumes `arg` is defined, in scope, and has 64-bit floating point type.

crates/web/src/pprint.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ impl<'a, O: Eq + Hash, T: Refs<'a, Opaque = O>> Function<'a, '_, O, T> {
158158
Expr::Field { tuple, member } => writeln!(f, "&x{}[{}]", tuple.var(), member.member())?,
159159
Expr::Unary { op, arg } => match op {
160160
Unop::Not => writeln!(f, "not x{}", arg.var())?,
161+
Unop::IMod => writeln!(f, "x{} mod T{}", arg.var(), self.def.vars[x].ty())?,
161162
Unop::Neg => writeln!(f, "-x{}", arg.var())?,
162163
Unop::Abs => writeln!(f, "|x{}|", arg.var())?,
163164
Unop::Sign => writeln!(f, "sign(x{})", arg.var())?,

packages/core/src/impl.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,14 @@ export const not = (p: Bool): Bool => {
930930
return newVar(ctx.block.not(ctx.func, boolId(ctx, p)));
931931
};
932932

933+
/** Return the modulus of the abstract index `i`. */
934+
export const imod = (ty: Nats, i: Nat): Nat => {
935+
const ctx = getCtx();
936+
const t = tyId(ctx, ty);
937+
const j = ctx.block.imod(ctx.func, t, valId(ctx, t, i));
938+
return idVal(ctx, t, j) as Nat;
939+
};
940+
933941
/** Return the conjunction of the abstract booleans `p` and `q`. */
934942
export const and = (p: Bool, q: Bool): Bool => {
935943
const ctx = getCtx();

packages/core/src/index.test.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
igt,
2222
ileq,
2323
ilt,
24+
imod,
2425
ineq,
2526
interp,
2627
jvp,
@@ -83,10 +84,6 @@ describe("invalid", () => {
8384
);
8485
});
8586

86-
test("out of bounds index", () => {
87-
expect(() => fn([Vec(2, Real)], Real, (v) => v[2])).toThrow("out of range");
88-
});
89-
9087
test("access index out of scope", () => {
9188
const n = 2;
9289
expect(() =>
@@ -1052,4 +1049,15 @@ describe("valid", () => {
10521049
expect(g(1, 1)).toBe(2);
10531050
expect(g(2, 0)).toBe(2);
10541051
});
1052+
1053+
test("index modulus", async () => {
1054+
const f = fn([], Vec(7, 3), () => {
1055+
const v = [];
1056+
for (let i = 0; i < 7; ++i) v.push(imod(3, i));
1057+
return v;
1058+
});
1059+
const expected = [0, 1, 2, 0, 1, 2, 0];
1060+
expect(interp(f)()).toEqual(expected);
1061+
expect((await compile(f))()).toEqual(expected);
1062+
});
10551063
});

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export {
3333
igt,
3434
ileq,
3535
ilt,
36+
imod,
3637
ineq,
3738
interp,
3839
jvp,

0 commit comments

Comments
 (0)