-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6aad0f3
commit 1298d06
Showing
9 changed files
with
469 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/target |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[package] | ||
name = "sfm-designer-solver" | ||
version = "0.1.0" | ||
edition = "2021" | ||
publish = false | ||
|
||
[dependencies] | ||
itertools = "0.13.0" | ||
|
||
[profile.release] | ||
lto = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# SFM Interferometer Designer Solver | ||
|
||
This is a solver used to generate the interferometer configurations for the app. | ||
Finding solutions is computationally hard, so these are pregenerated using an | ||
efficient Rust program. | ||
|
||
The solutions are generated in a format that can simply be pasted into the | ||
[Configuration.jsx](../src/model/Configuration.jsx). To generate the solutions, | ||
run | ||
|
||
```sh | ||
cargo run --release | ||
``` | ||
|
||
using the `--release` flag is recommended since it is over 10 times faster | ||
than debug mode. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
use std::ops::Index; | ||
|
||
/// A set of integers implemented as a sorted vector. | ||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] | ||
pub(crate) struct IntSet(Vec<usize>); | ||
|
||
impl IntSet { | ||
/// Create a new set from the given values. Duplicates are removed. | ||
pub(crate) fn from(mut values: Vec<usize>) -> Self { | ||
values.sort(); | ||
values.dedup(); | ||
Self(values) | ||
} | ||
|
||
/// The number of items in the set. | ||
pub(crate) fn len(&self) -> usize { | ||
self.0.len() | ||
} | ||
|
||
/// Get the items as a slice. | ||
pub(crate) fn as_slice(&self) -> &[usize] { | ||
self.0.as_slice() | ||
} | ||
|
||
/// Iterate over the items in ascending order. | ||
pub(crate) fn iter(&self) -> std::slice::Iter<usize> { | ||
self.as_slice().iter() | ||
} | ||
} | ||
|
||
impl Index<usize> for IntSet { | ||
type Output = usize; | ||
|
||
fn index(&self, index: usize) -> &Self::Output { | ||
&self.0[index] | ||
} | ||
} | ||
|
||
/// A multiset of integers implemented as a sorted vector. | ||
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] | ||
pub(crate) struct IntMultiset(Vec<usize>); | ||
|
||
impl IntMultiset { | ||
/// Create a new set from the given values. | ||
pub(crate) fn from(mut values: Vec<usize>) -> Self { | ||
values.sort(); | ||
Self(values) | ||
} | ||
|
||
/// The number of items in the set including duplicates. | ||
pub(crate) fn len(&self) -> usize { | ||
self.0.len() | ||
} | ||
|
||
/// Test whether this is a set, meaning there are no duplicates. | ||
pub(crate) fn is_set(&self) -> bool { | ||
// Since the values are sorted only adjacent values need to be compared. | ||
for i in 1..self.len() { | ||
if self.0[i] == self.0[i - 1] { | ||
return false; | ||
} | ||
} | ||
true | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
|
||
#[test] | ||
fn int_set_from() { | ||
assert_eq!(IntSet::from(vec![]), IntSet(vec![])); | ||
assert_eq!(IntSet::from(vec![1, 2, 3]), IntSet(vec![1, 2, 3])); | ||
assert_eq!(IntSet::from(vec![1, 2, 3, 2, 1]), IntSet(vec![1, 2, 3])); | ||
} | ||
|
||
#[test] | ||
fn int_set_len() { | ||
assert_eq!(0, IntSet::from(vec![]).len()); | ||
assert_eq!(3, IntSet::from(vec![1, 2, 3]).len()); | ||
assert_eq!(3, IntSet::from(vec![1, 2, 3, 2, 1]).len()); | ||
} | ||
|
||
#[test] | ||
fn int_set_as_slice() { | ||
let set = IntSet::from(vec![1, 2, 3]); | ||
let slice = set.as_slice(); | ||
assert_eq!(slice, [1, 2, 3]); | ||
} | ||
|
||
#[test] | ||
fn int_set_iter() { | ||
let set = IntSet::from(vec![1, 2, 3]); | ||
let mut it = set.iter(); | ||
assert_eq!(it.next(), Some(1).as_ref()); | ||
assert_eq!(it.next(), Some(2).as_ref()); | ||
assert_eq!(it.next(), Some(3).as_ref()); | ||
assert_eq!(it.next(), None); | ||
} | ||
|
||
#[test] | ||
fn int_set_index() { | ||
let set = IntSet::from(vec![1, 2, 5]); | ||
assert_eq!(set[0], 1); | ||
assert_eq!(set[1], 2); | ||
assert_eq!(set[2], 5); | ||
} | ||
|
||
#[test] | ||
fn intmultiset_from() { | ||
assert_eq!(IntMultiset::from(vec![]), IntMultiset(vec![])); | ||
assert_eq!(IntMultiset::from(vec![1, 2, 3]), IntMultiset(vec![1, 2, 3])); | ||
assert_eq!( | ||
IntMultiset::from(vec![1, 2, 3, 2, 1]), | ||
IntMultiset(vec![1, 1, 2, 2, 3]) | ||
); | ||
} | ||
|
||
#[test] | ||
fn int_multiset_len() { | ||
assert_eq!(0, IntMultiset::from(vec![]).len()); | ||
assert_eq!(3, IntMultiset::from(vec![1, 2, 3]).len()); | ||
assert_eq!(5, IntMultiset::from(vec![1, 2, 3, 2, 1]).len()); | ||
} | ||
|
||
#[test] | ||
fn int_multiset_is_set() { | ||
assert!(IntMultiset::from(vec![]).is_set()); | ||
assert!(IntMultiset::from(vec![1, 2, 3]).is_set()); | ||
assert!(!IntMultiset::from(vec![1, 2, 3, 2, 1]).is_set()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
mod int_set; | ||
mod model; | ||
|
||
use model::Solutions; | ||
|
||
fn main() { | ||
let max_size = 10; | ||
let mut largest = 1; | ||
println!("// DO NOT EDIT."); | ||
println!("// This file was automatically generated by sfm-designer-solver."); | ||
println!("//"); | ||
println!("// Each key in the solution is the number of reflections in the interferometer."); | ||
println!("const SOLUTIONS = {{"); | ||
for size in 2..=max_size { | ||
let solutions = Solutions::find_starting_at(size, largest); | ||
println!(" {}: [", size); | ||
solutions.iter().enumerate().for_each(|(index, lengths)| { | ||
println!( | ||
" {{ value: {}, solution: {:?}, name: '{:?}' }},", | ||
index, | ||
lengths.lengths().as_slice(), | ||
lengths.lengths().as_slice(), | ||
) | ||
}); | ||
println!(" ],"); | ||
if let Some(new_largest) = solutions | ||
.iter() | ||
.filter_map(|lengths| lengths.lengths().iter().max()) | ||
.max() | ||
{ | ||
largest = *new_largest; | ||
} | ||
largest = largest.max(size); | ||
} | ||
println!("}};"); | ||
println!(); | ||
println!("export default SOLUTIONS;"); | ||
} |
Oops, something went wrong.