Crates.io | grid1d |
lib.rs | grid1d |
version | 0.1.0 |
created_at | 2025-09-20 20:17:18.756586+00 |
updated_at | 2025-09-20 20:17:18.756586+00 |
description | A a mathematically rigorous, type-safe Rust library for 1D grid operations and interval partitions, supporting both native and arbitrary-precision numerics. |
homepage | |
repository | https://gitlab.com/max.martinelli/grid1d |
max_upload_size | |
id | 1848166 |
size | 1,445,583 |
One-dimensional grids and interval partitions with mathematical rigor and performance optimization.
grid1d
is a comprehensive Rust library for representing and manipulating one-dimensional grids, interval partitions and interval arithmetic with strong mathematical foundations, type safety, and performance optimizations. Designed for numerical computations, finite element methods, adaptive mesh refinement, and scientific computing applications requiring robust 1D spatial discretizations.
[a,b]
, (a,b)
, etc.) encode boundary semantics at compile timenum_valid::RealScalar
grid1d leverages the num-valid
library to provide multiple numerical backends with different precision and performance characteristics:
Backend | Scalar Type | Precision | Performance | Best For |
---|---|---|---|---|
Native | f64 |
53 bits | โกโกโก Maximum | Production simulations, real-time |
Native Validated (Debug) | RealNative64StrictFiniteInDebug |
53 bits | โกโกโก Same as f64 |
Recommended for most applications |
Native Validated | RealNative64StrictFinite |
53 bits | โกโก Small overhead | Safety-critical applications |
Arbitrary Precision | RealRugStrictFinite<N> |
N bits | โก Configurable | Scientific research, symbolic math |
This library requires Rust nightly for advanced language features:
# rust-toolchain.toml (automatically configured)
[toolchain]
channel = "nightly"
Why nightly is required:
#![feature(error_generic_member_access)]
): Better debugging and error contextAdd this to your Cargo.toml
:
[dependencies]
grid1d = "0.1.0" # change to the latest versione
# For arbitrary precision arithmetic
grid1d = { version = "0.1.0", features = ["rug"] } # change `version` to the latest available
use grid1d::{
Grid1D, IntervalPartition, HasCoords1D,
intervals::IntervalClosed,
scalars::{NumIntervals, IntervalId},
};
use sorted_vec::partial::SortedSet;
// Create uniform grid with equal spacing
let domain = IntervalClosed::new(0.0, 1.0);
let uniform_grid = Grid1D::uniform(domain.clone(), NumIntervals::try_new(4).unwrap());
assert_eq!(uniform_grid.coords().deref(), &[0.0, 0.25, 0.5, 0.75, 1.0]);
// Create non-uniform grid with custom spacing
let coords = SortedSet::from_unsorted(vec![0.0, 0.1, 0.5, 0.9, 1.0]);
let non_uniform_grid = Grid1D::try_from_sorted(domain, coords).unwrap();
// Both grids implement the same IntervalPartition trait
assert_eq!(uniform_grid.num_intervals().as_ref(), &4);
assert_eq!(non_uniform_grid.num_intervals().as_ref(), &4);
// Efficient point location
let interval_id = uniform_grid.find_interval_id_of_point(&0.3);
let interval = uniform_grid.interval(&interval_id);
use grid1d::{Grid1D, intervals::IntervalClosed, scalars::NumIntervals};
use num_valid::{RealNative64StrictFiniteInDebug, RealNative64StrictFinite};
use try_create::TryNew;
// Performance-optimal with debug safety (recommended)
type OptimalReal = RealNative64StrictFiniteInDebug;
let optimal_grid = Grid1D::uniform(
IntervalClosed::new(
OptimalReal::try_new(0.0).unwrap(),
OptimalReal::try_new(1.0).unwrap()
),
NumIntervals::try_new(4).unwrap()
);
// Always validated for safety-critical applications
type SafeReal = RealNative64StrictFinite;
let safe_grid = Grid1D::uniform(
IntervalClosed::new(
SafeReal::try_new(0.0).unwrap(),
SafeReal::try_new(1.0).unwrap()
),
NumIntervals::try_new(4).unwrap()
);
For applications requiring arbitrary precision arithmetic:
// Add to Cargo.toml:
// grid1d = { version = "0.1.0", features = ["rug"] }
use grid1d::{Grid1D, intervals::IntervalClosed, scalars::NumIntervals};
use num_valid::RealRugStrictFinite;
use try_create::TryNew;
// 256-bit precision arithmetic
type HighPrecisionReal = RealRugStrictFinite<256>;
let high_precision_grid = Grid1D::uniform(
IntervalClosed::new(
HighPrecisionReal::try_new(0.0).unwrap(),
HighPrecisionReal::try_new(1.0).unwrap()
),
NumIntervals::try_new(4).unwrap()
);
// All grid operations work seamlessly with arbitrary precision
let hp_1 = HighPrecisionReal::try_new(1.0).unwrap();
let hp_3 = HighPrecisionReal::try_new(3.0).unwrap();
let point = hp_1 / hp_3; // 1. / 3.
let interval_id = high_precision_grid.find_interval_id_of_point(&point);
use grid1d::{*, intervals::*, scalars::*};
let base_grid = Grid1D::uniform(IntervalClosed::new(0.0, 1.0), NumIntervals::try_new(4).unwrap());
// Uniform refinement: double resolution everywhere
let uniform_refinement = base_grid.refine_uniform(&PositiveNumPoints1D::try_new(1).unwrap());
assert_eq!(uniform_refinement.refined_grid().num_intervals().as_ref(), &8);
// Selective refinement: refine only specific intervals
let selective_plan = [
(IntervalId::new(1), PositiveNumPoints1D::try_new(2).unwrap()), // 3 sub-intervals
(IntervalId::new(3), PositiveNumPoints1D::try_new(1).unwrap()), // 2 sub-intervals
];
let selective_refinement = uniform_refinement.into_refined_grid().refine(&selective_plan);
use grid1d::{*, intervals::*, scalars::*};
use sorted_vec::partial::SortedSet;
let domain = IntervalClosed::new(0.0, 2.0);
// Physics A: coarse global grid
let grid_a = Grid1D::uniform(domain.clone(), NumIntervals::try_new(4).unwrap());
// Physics B: fine local grid
let coords_b = SortedSet::from_unsorted(vec![0.0, 0.3, 0.7, 1.1, 1.4, 2.0]);
let grid_b = Grid1D::try_from_sorted(domain, coords_b).unwrap();
// Create unified grid preserving mappings to both original grids
let union = Grid1DUnion::try_new(&grid_a, &grid_b).unwrap();
println!("Unified grid has {} intervals", union.num_refined_intervals().as_ref());
// Map data between grids
for (refined_id, a_id, b_id) in union.iter_interval_mappings() {
println!("Unified interval {} maps to A[{}] and B[{}]",
refined_id.as_ref(), a_id.as_ref(), b_id.as_ref());
}
use grid1d::intervals::*;
let closed = IntervalClosed::new(0.0, 1.0); // [0, 1]
let open = IntervalOpen::new(0.0, 1.0); // (0, 1)
let half_open = IntervalLowerClosedUpperOpen::new(0.0, 1.0); // [0, 1)
let unbounded = IntervalLowerClosedUpperUnbounded::new(0.0); // [0, +โ)
// All implement IntervalTrait for generic operations
assert!(closed.contains_point(&0.0));
assert!(!open.contains_point(&0.0));
Grid Type | Point Location | Memory | Best For |
---|---|---|---|
Grid1DUniform |
O(1) analytical | O(n) | Equal spacing, maximum performance |
Grid1DNonUniform |
O(log n) binary search | O(n) | Adaptive spacing, complex features |
Grid1DUnion |
O(log n) on unified grid | O(n+m) | Multi-physics, grid combination |
The library correctly handles different interval boundary semantics:
[a,b]
: Include both endpoints(a,b)
: Exclude both endpoints[a,b)
or (a,b]
- include one endpointEvery grid maintains these invariants:
use grid1d::{*, intervals::*, scalars::*};
let grid = Grid1D::uniform(IntervalClosed::new(0.0, 1.0), NumIntervals::try_new(100).unwrap());
let dx = grid.coords()[1] - grid.coords()[0];
// Apply finite difference stencils
for i in 1..grid.coords().len()-1 {
let d2u_dx2 = (solution[i-1] - 2.0*solution[i] + solution[i+1]) / (dx * dx);
// Time stepping logic...
}
use grid1d::{*, intervals::*};
// Periodic domain for Fourier spectral methods
let domain = IntervalLowerClosedUpperOpen::new(0.0, 2.0 * std::f64::consts::PI);
let grid = Grid1D::uniform(domain, NumIntervals::try_new(256).unwrap());
// Perfect for FFT algorithms
let dx = grid.coords()[1] - grid.coords()[0];
assert!((dx - 2.0 * std::f64::consts::PI / 256.0).abs() < 1e-15);
use grid1d::{*, intervals::*, scalars::*};
use sorted_vec::partial::SortedSet;
// Create boundary layer mesh with fine spacing near walls
fn create_boundary_layer_mesh(domain_length: f64, boundary_thickness: f64)
-> Grid1D<IntervalClosed<f64>>
{
let mut points = vec![0.0];
// Fine spacing in boundary layer
for i in 1..=20 {
let eta = (i as f64) / 20.0;
let y = boundary_thickness * (eta * eta); // Quadratic clustering
points.push(y);
}
// Coarse spacing in outer region
for i in 1..=10 {
let y = boundary_thickness + (domain_length - boundary_thickness) * (i as f64) / 10.0;
points.push(y);
}
Grid1D::try_from_sorted(
IntervalClosed::new(0.0, domain_length),
SortedSet::from_unsorted(points)
).unwrap()
}
let cfd_grid = create_boundary_layer_mesh(1.0, 0.1);
println!("CFD grid: {} intervals", cfd_grid.num_intervals().as_ref());
# Standard build (uses nightly automatically)
cargo build
# With arbitrary precision support
cargo build --features=rug
# Run tests
cargo test
# Run tests with arbitrary precision
cargo test --features=rug
# Generate documentation
cargo doc --open
rust-toolchain.toml
)num-valid
]: Validated scalar arithmeticsorted-vec
]: Efficient sorted container implementationserde
]: Serialization support for grid structuresnutype
]: Type-safe wrapper generationderive-more
]: Ergonomic derive macrosgetset
]: Automatic getter generationrug
]: Arbitrary precision arithmetic via the rug
library
--features=rug
num_valid::RealRugStrictFinite<N>
types for N-bit precisionThe library includes comprehensive test suites:
# Run all tests
cargo test
# Run tests with arbitrary precision
cargo test --features=rug
# Run property-based tests
cargo test --test property_tests
# Run benchmarks
cargo bench
Clone the repository:
git clone git@gitlab.com:max.martinelli/grid1d.git
cd grid1d
Ensure you have the required dependencies:
Run the test suite:
cargo test --all-features
Check formatting and linting:
cargo fmt --check
cargo clippy --all-features
This project is licensed under the MIT License - see the LICENSE file for details.
num-valid
]: Generic validated scalar arithmeticndarray
]: N-dimensional arrays for Rustnalgebra
]: Linear algebra libraryfaer
]: High-performance linear algebrapolars
]: Fast DataFrame libraryFor comprehensive API documentation, mathematical foundations, and advanced usage patterns:
grid1d is designed for:
Copyright 2023-2025, C.N.R. - Consiglio Nazionale delle Ricerche
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
If you enable the rug
feature, this project will depend on the rug
library, which is licensed under the LGPL-3.0 license. Activating this feature may introduce LGPL-3.0 requirements to your project. Please review the terms of the LGPL-3.0 license to ensure compliance.