grid1d 0.7.0

A mathematically rigorous, type-safe Rust library for 1D grid operations and interval partitions, supporting both native and arbitrary-precision numerics.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
#![deny(rustdoc::broken_intra_doc_links)]
#![feature(error_generic_member_access)]
#![feature(min_specialization)]

//! One-dimensional grids and interval partitions with mathematical rigor and performance optimization.
//!
//! This library provides a comprehensive framework for representing and manipulating
//! ***one-dimensional grids*** and ***interval partitions*** with strong mathematical
//! foundations, type safety, and performance optimizations. It serves as the backbone
//! for numerical computations, finite element methods, adaptive mesh refinement, and
//! scientific computing applications requiring robust 1D spatial discretizations.
//!
//! ## Core Design Philosophy
//!
//! ### Mathematical Correctness First
//! The library prioritizes **mathematical rigor** over convenience:
//! - **Type-safe intervals**: Different interval types ([`intervals::IntervalClosed`], [`intervals::IntervalOpen`], etc.) encode boundary semantics at compile time
//! - **Domain validation**: Runtime checks ensure grids completely partition their specified domains
//! - **Proper boundary handling**: Open/closed boundary semantics are correctly preserved in all operations
//! - **Generic scalar support**: Works with any scalar type implementing [`num_valid::RealScalar`]
//!
//! ### Multiple Floating-Point Backends via num-valid
//!
//! **grid1d** leverages the [`num-valid`](https://crates.io/crates/num-valid) library to provide **multiple numerical backends**
//! with different precision and performance characteristics:
//!
//! #### **Native Backend (Default)**
//! - **Base types**: [`f64`] for maximum performance with IEEE 754 compliance
//! - **Validated types**: [`num_valid::RealNative64StrictFinite`] for validation in Debug and Release mode,
//!   [`num_valid::RealNative64StrictFiniteInDebug`] for validation only in Debug mode
//! - **Performance**: ⚡⚡⚡ Maximum speed for [`num_valid::RealNative64StrictFiniteInDebug`] (same as `f64`) with O(1) operations
//! - **Precision**: Standard IEEE 754 double precision (53-bit mantissa)
//! - **Best for**: High-performance simulations, real-time applications
//!
//! #### **Arbitrary Precision Backend (Optional, activated with `--features=rug`)**
//! - **Base types**: [`rug::Float`](https://docs.rs/rug/latest/rug/float/struct.Float.html), [`rug::Complex`](https://docs.rs/rug/latest/rug/complex/struct.Complex.html) from the GNU Multiple Precision Arithmetic Library
//! - **Validated types**: `num_valid::RealRugStrictFinite<N>`
//! - **Performance**: ⚡ Configurable, depends on precision setting
//! - **Precision**: User-defined N-bit precision (e.g., 100, 256, 1024 bits)
//! - **Best for**: Scientific computing requiring exact arithmetic, symbolic computation
//!
//! **All grid operations work seamlessly across backends** - you can switch from standard
//! to arbitrary precision by simply changing the scalar type, with no changes to your
//! grid manipulation code.
//!
//! ```rust
//! use grid1d::{*, intervals::*};
//! use num_valid::{RealNative64StrictFinite, RealScalar};
//! use try_create::TryNew;
//!
//! // Standard precision grid
//! let domain = IntervalClosed::new(
//!     RealNative64StrictFinite::try_from_f64(0.0).unwrap(),
//!     RealNative64StrictFinite::try_from_f64(1.0).unwrap()
//! );
//! let standard_grid = Grid1D::uniform(domain, NumIntervals::try_new(100).unwrap());
//!
//! # #[cfg(feature = "rug")]
//! # {
//! use num_valid::RealRugStrictFinite;
//!
//! // High precision grid (256-bit precision) - same API!
//! let hp_domain = IntervalClosed::new(
//!     RealRugStrictFinite::<256>::try_from_f64(0.0).unwrap(),
//!     RealRugStrictFinite::<256>::try_from_f64(1.0).unwrap()
//! );
//! let high_precision_grid = Grid1D::uniform(hp_domain, NumIntervals::try_new(100).unwrap());
//!
//! // Both grids support identical operations
//! let point = RealRugStrictFinite::<256>::try_from_f64(0.5).unwrap();
//! let interval_id = high_precision_grid.find_interval_id_of_point(&point);
//! # }
//! ```
//!
//! ### Backend Selection Guide
//!
//! | Backend | Scalar Type | Precision | Performance | Use Case |
//! |---------|-------------|-----------|-------------|----------|
//! | **Native** | [`f64`] | 53 bits | ⚡⚡⚡ Maximum | Production simulations, real-time |
//! | **Native Validated (in Debug only)** | [`num_valid::RealNative64StrictFiniteInDebug`] | 53 bits | ⚡⚡⚡ Maximum (same as `f64`) | Most applications |
//! | **Native Validated** | [`num_valid::RealNative64StrictFinite`] | 53 bits | ⚡⚡ Small penalty | Safety-critical applications |
//! | **Arbitrary Precision** | `num_valid::RealRugStrictFinite<N>` | N bits | ⚡ Configurable | Scientific research, symbolic math |
//!
//! **Enabling arbitrary precision**: Add `features = ["rug"]` to your `Cargo.toml`:
//! ```toml
//! [dependencies]
//! grid1d = { version = "0.6.0", features = ["rug"] }
//! ```
//!
//! ### Performance Through Specialization
//! - **Uniform grids**: O(1) point location with analytical formulas ([`Grid1DUniform`])
//! - **Non-uniform grids**: O(log n) binary search with optimized data structures ([`Grid1DNonUniform`])
//! - **Memory efficiency**: Zero-cost abstractions and cache-friendly memory layouts
//! - **SIMD-ready**: Regular patterns enable vectorization optimizations
//!
//! #### Performance Comparison: Grid Operations
//!
//! | Operation | [`Grid1DUniform`] | [`Grid1DNonUniform`] | [`Grid1DUnion`] | Notes |
//! |-----------|------------------|---------------------|----------------|--------|
//! | **Construction** | O(n) | O(n) | O(n+m) | Union merges coordinates from two grids |
//! | **Point location** | **O(1)** ⚡ | O(log n) | O(log(n+m)) | Uniform uses direct calculation |
//! | **Interval access** | O(1) | O(1) | O(1) | All grid types support direct access by ID |
//! | **Batch point location** | **O(k)** ⚡ | O(k log n) | O(k log(n+m)) | k = number of points |
//! | **Coordinate access** | O(1) | O(1) | O(1) | Direct array indexing |
//! | **Domain check** | O(1) | O(1) | O(1) | Simple boundary comparison |
//! | **Memory footprint** | 8n + 40 bytes | 8n + 40 bytes | 8(n+m) + 16k + 80 bytes | k = mapping table size |
//! | **Cache efficiency** | ⚡⚡⚡ Excellent | ⚡⚡ Good | ⚡⚡ Good | Sequential memory layout |
//!
//! *Where n = number of grid points, m = points in second grid (for union), k = number of intervals*
//!
//! #### Scalar Type Performance Impact
//!
//! | Scalar Type | Overhead | Point Location (uniform) | Memory per Point | When to Use |
//! |-------------|----------|--------------------------|------------------|-------------|
//! | `f64` | **0%** baseline | ~1.2 ns | 8 bytes | Maximum performance, trusted inputs |
//! | [`num_valid::RealNative64StrictFiniteInDebug`] | **0%** in release | ~1.2 ns | 8 bytes | **Recommended default** |
//! | [`num_valid::RealNative64StrictFinite`] | ~5-10% | ~1.3 ns | 8 bytes | Safety-critical applications |
//! | `RealRugStrictFinite<256>` | ~100-500% | ~5-50 ns | 32+ bytes | Arbitrary precision needs |
//!
//! *Benchmarked on x86_64 with typical workloads. Actual performance varies by CPU and workload.*
//!
//! ### Composability and Integration
//! - **Trait-based design**: Core traits ([`Grid1DTrait`], [`HasDomain1D`], [`HasCoords1D`]) enable generic programming
//! - **Unified interface**: [`Grid1D`] enum provides seamless switching between uniform and non-uniform grids
//! - **Grid operations**: Union, refinement, and intersection operations with bidirectional mappings
//!
//! ## Quick Start Guide
//!
//! ### Creating Grids
//! ```rust
//! use grid1d::{
//!     Grid1D, HasCoords1D, Grid1DTrait, HasIntervalIdRange,
//!     intervals::*,
//!     scalars::{NumIntervals, IntervalId},
//! };
//! use sorted_vec::partial::SortedSet;
//! use std::ops::Deref;
//! use try_create::TryNew;
//!
//! // 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.3, 0.7, 0.9, 1.0]);
//! let non_uniform_grid = Grid1D::<IntervalClosed<f64>>::try_from_sorted(coords).unwrap();
//!
//! // Both grids implement the same Grid1DTrait trait
//! assert_eq!(uniform_grid.num_intervals().as_ref(), &4);
//! assert_eq!(non_uniform_grid.num_intervals().as_ref(), &4);
//! ```
//!
//! ### Point Location and Interval Access
//! ```rust
//! use grid1d::{*, intervals::*};
//! use try_create::TryNew;
//!
//! let grid = Grid1D::uniform(IntervalClosed::new(0.0, 10.0), NumIntervals::try_new(10).unwrap());
//!
//! // Point location
//! let interval_id = grid.find_interval_id_of_point(&3.7).unwrap();
//! println!("Point 3.7 is in interval {}", interval_id.as_ref());
//!
//! // Access interval properties
//! let interval = grid.interval(&interval_id);
//! let length = grid.interval_length(&interval_id);
//! println!("Interval length: {}", length.as_ref());
//!
//! // Batch point location
//! let points = vec![1.5, 4.2, 7.8, 9.1];
//! let intervals = grid.find_intervals_for_points(&points);
//! ```
//!
//! ### Working with Different Scalar Types
//! ```rust
//! use grid1d::{Grid1D, intervals::*, scalars::NumIntervals};
//! use num_valid::RealNative64StrictFiniteInDebug;
//! use try_create::TryNew;
//!
//! // Use validated scalar types for debug safety
//! type Real = RealNative64StrictFiniteInDebug;
//! let domain = IntervalClosed::new(
//!     Real::try_new(0.0).unwrap(),
//!     Real::try_new(1.0).unwrap()
//! );
//! let grid = Grid1D::uniform(domain, NumIntervals::try_new(100).unwrap());
//! ```
//!
//! ## Core Concepts
//!
//! ### Grid Types and Performance Characteristics
//!
//! | 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 |
//!
//! ### Interval Partition Types
//! The library correctly handles different interval boundary semantics:
//! - **Closed intervals `[a,b]`**: Include both endpoints
//! - **Open intervals `(a,b)`**: Exclude both endpoints  
//! - **Semi-open intervals**: `[a,b)` or `(a,b]` - include one endpoint
//! - **Automatic sub-interval construction**: Preserves domain semantics in partitions
//!
//! ### Mathematical Properties and Guarantees
//! Every grid maintains these invariants:
//! - **Complete domain coverage**: ⋃ intervals = domain (exact reconstruction)
//! - **Non-overlapping intervals**: Intervals are disjoint except at boundaries
//! - **Unique point location**: Every domain point belongs to exactly one interval
//! - **Boundary consistency**: First/last coordinates match domain bounds exactly
//! - **Sorted coordinates**: Points are in strict ascending order
//!
//! ## Advanced Features
//!
//! ### Adaptive Mesh Refinement
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use try_create::TryNew;
//! use std::collections::BTreeMap;
//!
//! 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 = BTreeMap::from([
//!     (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);
//! ```
//!
//! ### Grid Union for Multi-Physics
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use sorted_vec::partial::SortedSet;
//! use try_create::TryNew;
//!
//! let domain = IntervalClosed::new(0.0, 2.0);
//!
//! // Physics A: coarse global grid
//! let grid_a = Grid1D::uniform(domain, 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::<IntervalClosed<f64>>::try_from_sorted(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());
//! }
//! ```
//!
//! ### Point Classification
//!
//! [`CoordsByIntervalClassification`] maps each coordinate in a slice to the grid
//! interval that contains it, separating points that fall outside the domain.
//! This is the fundamental building block for FEM assembly, interpolation, and
//! adaptive mesh refinement.
//!
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use try_create::TryNew;
//!
//! let grid = Grid1D::uniform(
//!     IntervalClosed::new(0.0, 1.0),
//!     NumIntervals::try_new(4).unwrap(),
//! );
//!
//! let coords: Vec<f64> = vec![-0.1, 0.1, 0.3, 0.6, 0.9, 1.5];
//!
//! // Dense storage: pre-allocates one bucket per grid interval
//! let classification = CoordsByIntervalClassification::try_new_dense_from_coords(
//!     &coords, &grid,
//! ).unwrap();
//!
//! // Points outside [0, 1]
//! let outside = classification.point_ids_outside();
//! assert_eq!(outside.as_slice(), &[0, 5]); // indices of -0.1 and 1.5
//!
//! // Points inside each interval
//! for (interval_id, point_ids) in classification.point_ids_inside() {
//!     println!("Interval {}: {:?}", interval_id.as_ref(), point_ids.as_slice());
//! }
//! ```
//!
//! For large coordinate sets use the parallel variants
//! [`CoordsByIntervalClassification::try_new_dense_from_coords_par`] and
//! [`CoordsByIntervalClassification::try_new_sparse_from_coords_par`], which
//! classify points in parallel using Rayon. When coordinates are pre-sorted and
//! all lie within the domain, the zero-allocation
//! [`CoordsByIntervalClassification::new_dense_from_coords_sorted`] (or the sparse counterpart
//! [`CoordsByIntervalClassification::new_sparse_from_coords_sorted`]) provides the
//! fastest path.
//!
//! ### Domain-Specific Interval Semantics
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use sorted_vec::partial::SortedSet;
//!
//! // Closed domain: [0,2] includes both boundaries
//! let closed_grid = Grid1D::<IntervalClosed<f64>>::try_from_sorted(
//!     SortedSet::from_unsorted(vec![0.0, 1.0, 2.0])
//! ).unwrap();
//!
//! // Open domain: (0,2) excludes both boundaries  
//! let open_grid = Grid1D::<IntervalOpen<f64>>::try_from_sorted(
//!     SortedSet::from_unsorted(vec![0.0, 1.0, 2.0])
//! ).unwrap();
//!
//! // Different sub-interval types are automatically constructed
//! let closed_interval_0 = closed_grid.interval(&IntervalId::new(0)); // [0,1]
//! let open_interval_0 = open_grid.interval(&IntervalId::new(0));     // (0,1]
//!
//! // Point containment reflects domain semantics
//! use grid1d::intervals::IntervalTrait;
//! // Note: This is a simplified example - actual containment checking requires pattern matching
//! ```
//!
//! ### High-Performance Computations
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use try_create::TryNew;
//!
//! // Large uniform grid for finite difference methods
//! let grid = Grid1D::uniform(
//!     IntervalClosed::new(0.0, 1.0),
//!     NumIntervals::try_new(100_000).unwrap()
//! );
//!
//! // O(1) point location for uniform grids
//! let start = std::time::Instant::now();
//! let test_points: Vec<f64> = (0..10_000).map(|i| i as f64 / 10_000.0).collect();
//! let intervals: Vec<IntervalId> = test_points.iter()
//!     .map(|&p| grid.find_interval_id_of_point(&p).unwrap())
//!     .collect();
//! let elapsed = start.elapsed();
//! println!("Located {} points in {:?}", test_points.len(), elapsed);
//! ```
//!
//! ## Performance Characteristics
//!
//! ### Time Complexity Summary
//! | Operation | Uniform Grid | Non-Uniform Grid | Grid Union | Notes |
//! |-----------|-------------|------------------|------------|--------|
//! | **Grid Creation** | O(n) | O(n) | O(n+m) | Linear in point count |
//! | **Point Location** | **O(1)** | O(log n) | O(log n) | Uniform grids use analytical formulas |
//! | **Interval Access** | O(1) | O(1) | O(1) | Direct array indexing |
//! | **Intersection** | O(k) | O(log n + k) | O(log n + k) | Where k = result size |
//! | **Union Creation** | - | - | O(n+m) | Optimal merge algorithm |
//! | **Grid Refinement** | O(n×r) | O(n×r) | O(n×r) | Where r = refinement factor |
//!
//! ### Space Complexity
//! - **Coordinates storage**: O(n) for all grid types
//! - **Grid union mappings**: O(n+m) additional space for bidirectional mappings
//! - **Refinement structures**: O(refined intervals) for mapping preservation
//! - **Memory layout**: Cache-friendly contiguous arrays for optimal performance
//!
//! ## Integration with other numerical Ecosystem
//!
//! ### Scalar Type Recommendations
//! Choose scalar types based on your performance and safety requirements:
//!
//! ```rust
//! use grid1d::{Grid1D, intervals::*, scalars::NumIntervals};
//! use num_valid::{RealNative64StrictFiniteInDebug, RealNative64StrictFinite};
//! use try_create::TryNew;
//!
//! // Maximum performance (production)
//! let fast_grid = Grid1D::uniform(
//!     IntervalClosed::new(0.0_f64, 1.0_f64),
//!     NumIntervals::try_new(1000).unwrap()
//! );
//!
//! // Balanced performance + debug safety (recommended)
//! type Real = RealNative64StrictFiniteInDebug;
//! let safe_grid = Grid1D::uniform(
//!     IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap()),
//!     NumIntervals::try_new(1000).unwrap()
//! );
//!
//! // Always validated (safety-critical)
//! type SafeReal = RealNative64StrictFinite;
//! let secure_grid = Grid1D::uniform(
//!     IntervalClosed::new(SafeReal::try_new(0.0).unwrap(), SafeReal::try_new(1.0).unwrap()),
//!     NumIntervals::try_new(1000).unwrap()
//! );
//! ```
//!
//! ### Numerical Method Integration
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use try_create::TryNew;
//!
//! // Finite difference method setup
//! fn setup_finite_difference(domain: IntervalClosed<f64>, resolution: usize)
//!     -> (Grid1D<IntervalClosed<f64>>, Vec<f64>)
//! {
//!     let grid = Grid1D::uniform(domain, NumIntervals::try_new(resolution).unwrap());
//!     let solution = vec![0.0; grid.coords().len()];
//!     (grid, solution)
//! }
//!
//! // Spectral method with periodic boundaries
//! fn setup_spectral_method(n_modes: usize) -> Grid1D<IntervalLowerClosedUpperOpen<f64>> {
//!     let domain = IntervalLowerClosedUpperOpen::new(0.0, 2.0 * std::f64::consts::PI);
//!     Grid1D::uniform(domain, NumIntervals::try_new(n_modes).unwrap())
//! }
//! ```
//!
//! ## Error Handling and Validation
//!
//! ### Construction Error Types
//! The library provides detailed error information for debugging:
//!
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use sorted_vec::partial::SortedSet;
//!
//! // Insufficient points
//! let coords = SortedSet::from_unsorted(vec![0.0]); // Only one point
//! match Grid1D::<IntervalClosed<f64>>::try_from_sorted(coords) {
//!     Err(ErrorsGrid1D::RequiredAtLeastTwoDistinctPoints { num_points_provided, .. }) => {
//!         println!("Need at least 2 points, got {}", num_points_provided);
//!     }
//!     _ => unreachable!(),
//! }
//! ```
//!
//! ### Safe Construction Patterns
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use sorted_vec::partial::SortedSet;
//!
//! fn safe_grid_from_points(
//!     points: Vec<f64>,
//! ) -> Result<Grid1D<IntervalClosed<f64>>, String> {
//!     if points.len() < 2 {
//!         return Err("Need at least 2 points".to_string());
//!     }
//!     
//!     let coords = SortedSet::from_unsorted(points);
//!     Grid1D::try_from_sorted(coords)
//!         .map_err(|e| format!("Grid construction failed: {}", e))
//! }
//! ```
//!
//! ## Common Pitfalls and How to Avoid Them
//!
//! ### Pitfall 1: Assuming All Grids Are Uniform
//! **Problem**: Trying to access uniform-specific methods on non-uniform grids.
//!
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use sorted_vec::partial::SortedSet;
//! use try_create::TryNew;
//!
//! let coords = SortedSet::from_unsorted(vec![0.0, 0.1, 0.5, 1.0]);
//! let grid = Grid1D::<IntervalClosed<f64>>::try_from_sorted(coords).unwrap();
//!
//! // ERROR: grid is NonUniform, not Uniform!
//! // let delta = grid.delta_points(); // This won't compile
//! ```
//!
//! **Solution**: Use pattern matching or trait methods:
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use sorted_vec::partial::SortedSet;
//! use try_create::TryNew;
//!
//! let coords = SortedSet::from_unsorted(vec![0.0, 0.1, 0.5, 1.0]);
//! let grid = Grid1D::<IntervalClosed<f64>>::try_from_sorted(coords).unwrap();
//!
//! // Correct: Use pattern matching
//! match &grid {
//!     Grid1D::Uniform(uniform_grid) => {
//!         let delta = uniform_grid.delta_points();
//!         println!("Uniform spacing: {}", delta);
//!     }
//!     Grid1D::NonUniform(_) => {
//!         println!("Non-uniform grid - use general methods");
//!     }
//! }
//!
//! // Or use trait methods that work for all grid types
//! let interval_id = grid.find_interval_id_of_point(&0.3); // Works for both uniform and non-uniform
//! ```
//!
//! ### Pitfall 2: Boundary Point Confusion with Open Intervals
//! **Problem**: Assuming boundary points are always contained in the domain.
//!
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use try_create::TryNew;
//!
//! // Open interval (0, 1) excludes both 0.0 and 1.0
//! let grid = Grid1D::uniform(
//!     IntervalOpen::new(0.0, 1.0),
//!     NumIntervals::try_new(4).unwrap()
//! );
//!
//! // 0.0 is NOT in the open interval!
//! let id = grid.find_interval_id_of_point(&0.0);
//! assert!(id.is_none());
//! ```
//!
//! ### Pitfall 3: Mixing Different Scalar Types
//! **Problem**: Trying to compare or combine grids with different scalar types.
//!
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use num_valid::RealNative64StrictFinite;
//! use try_create::TryNew;
//!
//! let grid_f64 = Grid1D::uniform(
//!     IntervalClosed::new(0.0_f64, 1.0_f64),
//!     NumIntervals::try_new(10).unwrap()
//! );
//!
//! let grid_validated = Grid1D::uniform(
//!     IntervalClosed::new(
//!         RealNative64StrictFinite::try_new(0.0).unwrap(),
//!         RealNative64StrictFinite::try_new(1.0).unwrap()
//!     ),
//!     NumIntervals::try_new(10).unwrap()
//! );
//!
//! // ERROR: Cannot create union of grids with different scalar types
//! // let union = Grid1DUnion::try_new(&grid_f64, &grid_validated);
//! ```
//!
//! **Solution**: Use consistent scalar types throughout your code:
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use num_valid::RealNative64StrictFiniteInDebug;
//! use try_create::TryNew;
//!
//! // Choose one scalar type and use it consistently
//! type Real = RealNative64StrictFiniteInDebug;
//!
//! let grid1 = Grid1D::uniform(
//!     IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(1.0).unwrap()),
//!     NumIntervals::try_new(10).unwrap()
//! );
//!
//! let grid2 = Grid1D::uniform(
//!     IntervalClosed::new(Real::try_new(0.0).unwrap(), Real::try_new(2.0).unwrap()),
//!     NumIntervals::try_new(20).unwrap()
//! );
//!
//! // Now operations between grids work correctly
//! // let union = Grid1DUnion::try_new(&grid1, &grid2); // Would work if domains matched
//! ```
//!
//! ### Pitfall 4: Inefficient Point Location in Loops
//! **Problem**: Repeatedly calling point location for sequential points.
//!
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use try_create::TryNew;
//!
//! let grid = Grid1D::uniform(
//!     IntervalClosed::new(0.0, 1.0),
//!     NumIntervals::try_new(1000).unwrap()
//! );
//!
//! let points: Vec<f64> = (0..1000).map(|i| i as f64 / 1000.0).collect();
//!
//! // Inefficient: Individual calls in a loop
//! for point in &points {
//!     let _ = grid.find_interval_id_of_point(point);
//! }
//! ```
//!
//! **Solution**: Use batch operations when available:
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use try_create::TryNew;
//!
//! let grid = Grid1D::uniform(
//!     IntervalClosed::new(0.0, 1.0),
//!     NumIntervals::try_new(1000).unwrap()
//! );
//!
//! let points: Vec<f64> = (0..1000).map(|i| i as f64 / 1000.0).collect();
//!
//! // Efficient: Batch operation
//! let interval_ids = grid.find_intervals_for_points(&points);
//! ```
//!
//! ### Pitfall 5: Pattern Matching on Interval Enums
//! **Problem**: Working with heterogeneous interval collections or runtime-determined interval types.
//!
//! The [`Interval`] enum wraps all interval types for uniform handling,
//! but requires pattern matching to access type-specific functionality.
//!
//! ```rust
//! use grid1d::intervals::*;
//!
//! // Creating intervals of different types
//! let closed = IntervalClosed::new(0.0, 1.0);
//! let open = IntervalOpen::new(0.0, 1.0);
//! let half_open = IntervalLowerClosedUpperOpen::new(0.0, 1.0);
//!
//! // Convert to universal Interval enum for uniform handling
//! let intervals: Vec<Interval<f64>> = vec![
//!     closed.into(),
//!     open.into(),
//!     half_open.into(),
//! ];
//!
//! // Pattern matching on Interval enum
//! for interval in &intervals {
//!     match interval {
//!         Interval::FiniteLength(finite) => {
//!             // Further pattern matching on finite length variants
//!             match finite {
//!                 IntervalFiniteLength::PositiveLength(pos_len) => {
//!                     match pos_len {
//!                         IntervalFinitePositiveLength::Closed(closed) => {
//!                             println!("[{}, {}]", closed.lower_bound_value(), closed.upper_bound_value());
//!                         }
//!                         IntervalFinitePositiveLength::Open(open) => {
//!                             println!("({}, {})", open.lower_bound_value(), open.upper_bound_value());
//!                         }
//!                         IntervalFinitePositiveLength::LowerClosedUpperOpen(hco) => {
//!                             println!("[{}, {})", hco.lower_bound_value(), hco.upper_bound_value());
//!                         }
//!                         IntervalFinitePositiveLength::LowerOpenUpperClosed(hoc) => {
//!                             println!("({}, {}]", hoc.lower_bound_value(), hoc.upper_bound_value());
//!                         }
//!                     }
//!                 }
//!                 IntervalFiniteLength::ZeroLength(singleton) => {
//!                     println!("{{{}}}", singleton.value());
//!                 }
//!             }
//!         }
//!         Interval::InfiniteLength(infinite) => {
//!             println!("Unbounded interval: {:?}", infinite);
//!         }
//!     }
//! }
//! ```
//!
//! **Solution for common operations**: Use trait methods that work across all interval types:
//! ```rust
//! use grid1d::intervals::*;
//!
//! let intervals: Vec<Interval<f64>> = vec![
//!     IntervalClosed::new(0.0, 1.0).into(),
//!     IntervalOpen::new(2.0, 3.0).into(),
//!     IntervalLowerClosedUpperOpen::new(4.0, 5.0).into(),
//! ];
//!
//! // Use trait methods for common operations without pattern matching
//! for interval in &intervals {
//!     // contains_point works on all interval types via IntervalTrait
//!     let contains_half = interval.contains_point(&0.5);
//!     println!("Contains 0.5: {}", contains_half);
//!
//!     // Get bounds info using GetLeftValue/GetRightValue traits
//!     // (only for bounded intervals)
//!     if let Interval::FiniteLength(finite) = interval {
//!         match finite {
//!             IntervalFiniteLength::PositiveLength(pos) => {
//!                 let length = pos.length();
//!                 println!("Length: {}", length.as_ref());
//!             }
//!             IntervalFiniteLength::ZeroLength(_) => {
//!                 println!("Length: 0 (singleton)");
//!             }
//!         }
//!     }
//! }
//! ```
//!
//! **Simplified approach for finite intervals only**:
//! ```rust
//! use grid1d::intervals::*;
//!
//! // If you only work with finite positive-length intervals, use IntervalFinitePositiveLength
//! let finite_intervals: Vec<IntervalFinitePositiveLength<f64>> = vec![
//!     IntervalClosed::new(0.0, 1.0).into(),
//!     IntervalOpen::new(2.0, 3.0).into(),
//! ];
//!
//! for interval in &finite_intervals {
//!     // length() is available directly on IntervalFinitePositiveLength
//!     let len = interval.length();
//!     let mid = interval.midpoint();
//!     println!("Length: {}, Midpoint: {}", len.as_ref(), mid);
//! }
//! ```
//!
//! ## Best Practices and Recommendations
//!
//! ### When to Use Each Grid Type
//!
//! **Use [`Grid1DUniform`] when:**
//! - Finite difference methods requiring equal spacing
//! - Spectral methods with uniform point distributions
//! - Maximum performance is critical (O(1) point location)
//! - Simple problems with uniform solution characteristics
//!
//! **Use [`Grid1DNonUniform`] when:**
//! - Adaptive mesh refinement based on solution features
//! - Boundary layer resolution in fluid dynamics
//! - Multi-scale problems requiring variable resolution
//! - Complex geometries or irregular point distributions
//!
//! **Use [`Grid1DUnion`] when:**
//! - Combining grids from different physics solvers
//! - Multi-physics coupling requiring consistent discretization
//! - Grid overlay operations for interpolation
//! - Preserving relationships between multiple grid levels
//!
//! ### Performance Optimization Tips
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use try_create::TryNew;
//!
//! // 1. Choose uniform grids when possible for O(1) point location
//! let uniform_grid = Grid1D::uniform(
//!     IntervalClosed::new(0.0, 1.0),
//!     NumIntervals::try_new(1000).unwrap()
//! );
//!
//! // 2. Use batch operations for multiple points
//! let points = vec![0.1, 0.3, 0.7, 0.9];
//! let intervals = uniform_grid.find_intervals_for_points(&points); // More efficient than individual calls
//!
//! // 3. Pre-allocate vectors for performance-critical loops
//! let mut results = Vec::with_capacity(points.len());
//! for &point in &points {
//!     results.push(uniform_grid.find_interval_id_of_point(&point));
//! }
//!
//! // 4. Use direct coordinate access for sequential processing
//! let coords = uniform_grid.coords().as_ref();
//! for i in 0..coords.len()-1 {
//!     let interval_length = coords[i+1] - coords[i];
//!     // Process interval...
//! }
//! ```
//!
//! ### Memory Management
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use try_create::TryNew;
//!
//! // For large grids, consider the memory footprint
//! let large_grid = Grid1D::uniform(
//!     IntervalClosed::new(0.0, 1.0),
//!     NumIntervals::try_new(1_000_000).unwrap()
//! );
//!
//! // Memory usage: ~8MB for coordinates (1M points × 8 bytes/f64)
//! println!("Grid memory: ~{} MB",
//!          large_grid.coords().len() * std::mem::size_of::<f64>() / 1_000_000);
//!
//! // Use iterators to avoid creating intermediate vectors
//! let sum: f64 = large_grid.coords().iter().sum();
//! let mean = sum / large_grid.coords().len() as f64;
//! ```
//!
//! ## Related Modules and Integration
//!
//! This module integrates with the other numerical ecosystem:
//!
//! - **[`crate::coords`]**: Coordinate collections and point-transformation traits
//!   ([`Coords1D`], [`Coords1DInDomain`], [`TransformedCoords1D`], and storage-variant aliases)
//! - **[`crate::grids`]**: Concrete grid types with performance specialization (three submodules):
//!   - **[`crate::grids`]** itself: [`Grid1DUniform`], [`Grid1DNonUniform`], [`Grid1D`], [`ErrorsGrid1D`]
//!   - **[`crate::grids::traits`]**: Core grid traits ([`Grid1DTrait`], [`HasDomain1D`], [`HasCoords1D`], etc.) re-exported at the crate root
//!   - **[`crate::grids::window`]**: [`Grid1DWindow`] — zero-copy borrowed view over a contiguous interval sub-range
//! - **[`crate::intervals`]**: Interval types with compile-time boundary semantics
//! - **[`crate::scalars`]**: Type-safe wrappers for numerical quantities
//! - **[`crate::bounds`]**: Low-level boundary representation
//! - **[`crate::topology`]**: Topology types, index spaces, and adjacency queries
//! - **[`crate::operations`]**: Advanced grid operations (three submodules):
//!   - **[`crate::operations::refinement`]**: Interval subdivision and AMR with parent–child mappings
//!   - **[`crate::operations::union`]**: Grid combination with bidirectional interval mappings
//!   - **[`crate::operations::point_classification`]**: Classifies coordinate slices by grid interval ([`CoordsByIntervalClassification`])
//! - **[`num_valid`]**: Generic scalar arithmetic and validation
//! - **[`sorted_vec`]**: Efficient sorted container implementation
//!
//! ### Future Extensions
//! The design supports natural extensions to:
//! - **Multi-dimensional grids**: 2D/3D generalizations using the same principles
//! - **Adaptive algorithms**: Error-driven refinement strategies
//! - **Parallel processing**: Thread-safe grid operations and domain decomposition
//! - **GPU acceleration**: SIMD-friendly data layouts for vectorization
//! - **File I/O**: Serialization for large-scale scientific computing
//!
//! ## Examples and Use Cases
//!
//! ### Computational Fluid Dynamics
//! ```rust
//! 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::<IntervalClosed<f64>>::try_from_sorted(
//!         SortedSet::from_unsorted(points)
//!     ).unwrap()
//! }
//!
//! let cfd_grid = create_boundary_layer_mesh(1.0, 0.1);
//! println!("CFD grid: {} intervals, min spacing: {:.2e}",
//!          cfd_grid.num_intervals().as_ref(),
//!          cfd_grid.min_interval_length().as_ref());
//! ```
//!
//! ### Adaptive Finite Element Analysis
//! ```rust
//! use grid1d::{*, intervals::*, scalars::*};
//! use try_create::TryNew;
//!
//! // Simulate adaptive refinement based on error indicators
//! fn adaptive_fem_cycle(
//!     mut grid: Grid1D<IntervalClosed<f64>>,
//!     error_threshold: f64,
//!     max_iterations: usize
//! ) -> Grid1D<IntervalClosed<f64>> {
//!     for iteration in 0..max_iterations {
//!         // Compute error indicators (simplified)
//!         let errors: Vec<f64> = (0..*grid.num_intervals().as_ref())
//!             .map(|i| {
//!                 // Simulate error based on interval size (larger intervals = higher error)
//!                 grid.interval_length(&IntervalId::new(i)).as_ref() * 10.0
//!             })
//!             .collect();
//!         
//!         // Mark intervals for refinement
//!         let refinement_plan: std::collections::BTreeMap<IntervalId, PositiveNumPoints1D> = errors
//!             .iter()
//!             .enumerate()
//!             .filter_map(|(i, &error)| {
//!                 if error > error_threshold {
//!                     Some((IntervalId::new(i), PositiveNumPoints1D::try_new(1).unwrap()))
//!                 } else {
//!                     None
//!                 }
//!             })
//!             .collect();
//!         
//!         if refinement_plan.is_empty() {
//!             println!("Converged after {} iterations", iteration);
//!             break;
//!         }
//!         
//!         // Apply refinement
//!         let refinement = grid.refine(&refinement_plan);
//!         grid = Grid1D::NonUniform(refinement.into_refined_grid());
//!         
//!         println!("Iteration {}: refined {} intervals, total: {}",
//!                  iteration, refinement_plan.len(), grid.num_intervals().as_ref());
//!     }
//!     
//!     grid
//! }
//! ```
//!
//! For comprehensive examples, API documentation, and advanced usage patterns,
//! see the individual struct and trait documentation throughout this module.

pub mod bounds;

pub mod coords;
pub use coords::{
    Coords1D, Coords1DInDomain, Coords1DInDomainArc, Coords1DInDomainBorrowed, Coords1DInDomainBox,
    Coords1DInDomainCow, Coords1DInDomainOwned, Coords1DInDomainRc, ErrorsCoords1D,
    ErrorsCoords1DInDomain, TransformedCoords1D, TransformedCoords1DArc,
    TransformedCoords1DBorrowed, TransformedCoords1DOwned, TransformedCoords1DRc,
    linspace_on_closure, logspace, sort_dedup_with_map,
};

pub mod grids;
pub use grids::{
    ErrorsGrid1D, FindIntervalIdOfPoint, Grid1D, Grid1DIntervalBuilder, Grid1DNonUniform,
    Grid1DTrait, Grid1DUniform, HasCoordIdRange, HasCoords1D, HasDomain1D, HasIntervalIdRange,
    HasIntervals,
    window::{ErrorsGrid1DWindow, Grid1DWindow},
};

pub mod intervals;
pub use intervals::{
    ContainsInterval, ContainsPoint1D, GetLowerBoundValue, GetUpperBoundValue, IntervalBounded,
    IntervalBoundsRuntime, IntervalClosed, IntervalDifference, IntervalFiniteLength,
    IntervalFiniteLengthTrait, IntervalFinitePositiveLength, IntervalFinitePositiveLengthTrait,
    IntervalFromBounds, IntervalHull, IntervalInfiniteLength, IntervalInfiniteLengthTrait,
    IntervalLowerBoundedUpperUnboundedTrait, IntervalLowerClosedUpperOpen,
    IntervalLowerClosedUpperUnbounded, IntervalLowerOpenUpperClosed,
    IntervalLowerOpenUpperUnbounded, IntervalLowerUnboundedUpperBoundedTrait,
    IntervalLowerUnboundedUpperClosed, IntervalLowerUnboundedUpperOpen,
    IntervalLowerUnboundedUpperUnbounded, IntervalOpen, IntervalPositiveLengthTrait,
    IntervalSingleton, IntervalTrait, IntervalUnion, IntervalZeroLengthTrait,
    SubIntervalInPartition, Translate1D,
};

pub mod operations;
pub use operations::{
    point_classification::{
        CoordIdsByInterval, CoordsByIntervalClassification, ErrorsCoordsByIntervalClassification,
    },
    refinement::{Grid1DNonUniformRefinement, Grid1DRefinement, Grid1DUniformRefinement},
    union::{ErrorsGrid1DUnion, Grid1DUnion},
};

pub mod prelude;

pub mod scalars;
pub use scalars::{CoordId, IndexId, IntervalId, NumIntervals, PositiveNumPoints1D, PositiveSize};

pub mod topology;
pub use topology::{
    Adjacency1D, CoordIndexSpace1D, Grid1DIndexSpaces, HasSide, IndexSpace1D, IntervalIndexSpace1D,
    IntervalSide, Neighbors1D, Side, Topology1D,
};

use crate::{
    intervals::{ErrorsIntervalConstruction, Interval},
    scalars::ErrorsPositiveInt,
    topology::sealed::SupportsCircularTopology,
};
use num_valid::RealScalar;

//--------------------------------------------------------------------------------------------------------------------
/// Base trait for types that have an associated coordinate (real scalar) type.
///
/// It separates the declaration of the coordinate scalar type
/// from the rest of the other contracts, so that:
///
/// - code that only needs to know *what kind of scalar a type uses* can depend solely on
///   `HasCoordType` without importing the full evaluation machinery;
/// - constraints of the type `IntervalType: IntervalTrait<CoordType = CoordType>` in some traits is expressed once and always consistent.
///
/// ## Associated type
///
/// | Type | Bound | Description |
/// |---|---|---|
/// | `CoordType` | [`RealScalar`] | Real scalar type used for evaluation-point coordinates |
///
/// ```rust
/// use grid1d::HasCoordType;
///
/// struct MyData;
///
/// impl HasCoordType for MyData {
///     type CoordType = f64;
/// }
/// ```
pub trait HasCoordType {
    type CoordType: RealScalar;
}
//--------------------------------------------------------------------------------------------------------------------