Skip to content

Commit b4ecd9d

Browse files
authored
Merge pull request #42 from TorBorve/bugs/norms-dim-zero
Bugs/norms dim zero and new clippy version
2 parents b12d114 + 361c9f7 commit b4ecd9d

9 files changed

Lines changed: 105 additions & 72 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "control_systems_torbox"
3-
version = "0.2.0"
3+
version = "0.2.1"
44
edition = "2024"
55
authors = ["Tor Børve Rasmussen <tor.jobb.skule@gmail.com>"]
66
description = "Control systems toolbox"

build.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn main() {
1313
.to_string();
1414
let make_args: Vec<String> = vec![
1515
"-j8".to_string(),
16-
format!("BUILD_DIR={}", slicot_build_dir).to_string(),
16+
format!("BUILD_DIR={slicot_build_dir}").to_string(),
1717
];
1818

1919
let status = make()
@@ -32,7 +32,7 @@ fn main() {
3232
panic!("Failed to build SLICOT")
3333
}
3434

35-
println!("cargo:rustc-link-search={}", slicot_build_dir);
35+
println!("cargo:rustc-link-search={slicot_build_dir}");
3636
println!("cargo:rustc-link-lib=static=slicot");
3737
println!("cargo:rustc-link-lib=static=lpkaux");
3838
println!("cargo:rustc-link-lib=gfortran");

src/analysis/frequency_response.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,7 @@ fn freq_response_ss_mat(
254254

255255
if info != 0 {
256256
return Err(format!(
257-
"Failed to compute frequency response of state space system. Slicot TB05AD failed with error code: {}",
258-
info
257+
"Failed to compute frequency response of state space system. Slicot TB05AD failed with error code: {info}"
259258
));
260259
}
261260

src/analysis/system_properties.rs

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ fn h2_norm<U: Time + 'static>(
5050
let m = b.ncols();
5151
let p = c.nrows();
5252

53+
assert!(m > 0);
54+
assert!(p > 0);
55+
56+
if n == 0 {
57+
let d_all_zero = d.iter().all(|&x| x == 0.0);
58+
if d_all_zero {
59+
return Ok(0.);
60+
}
61+
return Err("Order of system is zero and D matrix is not zero".into());
62+
}
63+
5364
let lda = a.nrows();
5465
let ldb = b.nrows();
5566
let ldc = c.nrows();
@@ -66,6 +77,7 @@ fn h2_norm<U: Time + 'static>(
6677
let mut iwarn = -1 as c_int;
6778
let mut info = -1 as c_int;
6879

80+
// println!("lda: {}", lda);
6981
let h2_norm = unsafe {
7082
ab13bd_(
7183
time_domain.as_ptr(),
@@ -92,13 +104,11 @@ fn h2_norm<U: Time + 'static>(
92104

93105
if info != 0 {
94106
return Err(Box::new(std::io::Error::other(format!(
95-
"SLICOT ab13bd failed with the follwing error indicator: {}",
96-
info
107+
"SLICOT ab13bd failed with the follwing error indicator: {info}"
97108
))));
98109
} else if iwarn != 0 {
99110
return Err(Box::new(std::io::Error::other(format!(
100-
"SLICOT ab13bd returned with warning about numerical stability. Iwarn = {}",
101-
iwarn
111+
"SLICOT ab13bd returned with warning about numerical stability. Iwarn = {iwarn}"
102112
))));
103113
}
104114

@@ -122,6 +132,21 @@ fn hinf_norm<U: Time + 'static>(
122132
) -> Result<f64, String> {
123133
Ss::<U>::verify_dimensions(&a, &b, &c, &d).map_err(|e| e.to_string())?;
124134

135+
let n = a.nrows();
136+
let m = b.ncols();
137+
let p = c.nrows();
138+
139+
assert!(p > 0);
140+
assert!(m > 0);
141+
142+
if n == 0 {
143+
// The gain is constant and equal to D
144+
// H-inf norm is the largest singular value
145+
let singular_values = d.singular_values();
146+
let max_singular_value = singular_values.max();
147+
return Ok(max_singular_value);
148+
}
149+
125150
let time_domain = if std::any::TypeId::of::<U>()
126151
== std::any::TypeId::of::<Continuous>()
127152
{
@@ -137,10 +162,6 @@ fn hinf_norm<U: Time + 'static>(
137162
let equilibration = CString::new("S").unwrap(); // Perform scaling
138163
let d_is_nonzero = CString::new("D").unwrap();
139164

140-
let n = a.nrows();
141-
let m = b.ncols();
142-
let p = c.nrows();
143-
144165
let mut e = DMatrix::identity(n, n);
145166

146167
let mut f_peak = [0.0, 1.0]; // initial guess not active
@@ -199,8 +220,7 @@ fn hinf_norm<U: Time + 'static>(
199220

200221
if info != 0 {
201222
return Err(format!(
202-
"SLICOT ab13dd returned with error code. info = {}",
203-
info
223+
"SLICOT ab13dd returned with error code. info = {info}"
204224
));
205225
}
206226

@@ -293,8 +313,7 @@ pub fn zeros(
293313

294314
if info != 0 {
295315
return Err(format!(
296-
"SLICOT failed to find zeros of state-space system. Info = {}",
297-
info
316+
"SLICOT failed to find zeros of state-space system. Info = {info}"
298317
));
299318
}
300319
let ldwork = dwork[0] as usize;
@@ -336,8 +355,7 @@ pub fn zeros(
336355

337356
if info != 0 {
338357
return Err(format!(
339-
"SLICOT failed to find zeros of state-space system. Info = {}",
340-
info
358+
"SLICOT failed to find zeros of state-space system. Info = {info}"
341359
));
342360
}
343361
if num_inv_zeros == 0 {
@@ -384,7 +402,7 @@ pub fn zeros(
384402
);
385403
}
386404
if info != 0 {
387-
return Err(format!("LAPACK DGGEV returned info = {}", info));
405+
return Err(format!("LAPACK DGGEV returned info = {info}"));
388406
}
389407
lwork = dwork[0] as c_int;
390408
assert!(lwork > 0);
@@ -413,7 +431,7 @@ pub fn zeros(
413431
);
414432
}
415433
if info != 0 {
416-
return Err(format!("LAPACK DGGEV returned info = {}", info));
434+
return Err(format!("LAPACK DGGEV returned info = {info}"));
417435
}
418436

419437
let mut zeros = Vec::with_capacity(n_gen_eigen);
@@ -446,6 +464,7 @@ impl<U: Time + 'static> Ss<U> {
446464
/// - `Ok(f64)`: The H2 norm of the system.
447465
/// - `Err(String)`: An error message if the computation fails.
448466
pub fn norm_h2(&self) -> Result<f64, String> {
467+
// println!("before h2: {}", self);
449468
h2_norm::<U>(
450469
self.a().clone(),
451470
self.b().clone(),
@@ -510,6 +529,7 @@ impl<U: Time + 'static> Ss<U> {
510529
#[cfg(test)]
511530
mod tests {
512531
use crate::{
532+
Continuous, Ss,
513533
systems::Tf,
514534
transformations::SsRealization::{ControllableCF, ObservableCF},
515535
};
@@ -546,6 +566,13 @@ mod tests {
546566
epsilon = 1e-2
547567
);
548568
}
569+
570+
let sys = Ss::<Continuous>::new_from_scalar(-2.0);
571+
assert_abs_diff_eq!(sys.norm_hinf().unwrap(), 2.0);
572+
573+
assert!(sys.norm_h2().is_err());
574+
let sys = Ss::<Continuous>::new_from_scalar(0.0);
575+
assert_eq!(sys.norm_h2().unwrap(), 0.0);
549576
}
550577

551578
#[test]
@@ -592,9 +619,9 @@ mod tests {
592619
#[test]
593620
fn ss_zeros() {
594621
let tf = (Tf::s() - 1.0) * (Tf::s() + 4.0) / (Tf::s() + 2.0).powi(2);
595-
println!("tf: \n{}", tf);
622+
println!("tf: \n{tf}");
596623
let zeros = tf.to_ss_method(ControllableCF).unwrap().zeros().unwrap();
597-
println!("zeros: {:?}", zeros);
624+
println!("zeros: {zeros:?}");
598625
assert_eq!(zeros.len(), 2);
599626

600627
let tf = 1.0 / Tf::s();
@@ -643,18 +670,18 @@ mod tests {
643670
#[test]
644671
fn ss_is_stable() {
645672
let tf = 1.0 / Tf::s();
646-
assert_eq!(tf.to_ss_method(ObservableCF).unwrap().is_stable(), false);
673+
assert!(!tf.to_ss_method(ObservableCF).unwrap().is_stable());
647674

648675
let tf = (Tf::s() + 1.0) / (Tf::s() + 1.0).powi(4);
649676
let ss = tf.to_ss_method(ObservableCF).unwrap();
650-
assert_eq!(ss.is_stable(), true);
677+
assert!(ss.is_stable());
651678

652679
let tf = 1.0 / ((Tf::s() + 1.0) * (Tf::s() - 2.0));
653680
let ss = tf.to_ss_method(ObservableCF).unwrap();
654-
assert_eq!(ss.is_stable(), false);
681+
assert!(!ss.is_stable());
655682

656683
let tf = 1.0 / (Tf::s().powi(2) + 2.0 * 0.01 * Tf::s() + 1.0);
657684
let ss = tf.to_ss_method(ObservableCF).unwrap();
658-
assert_eq!(ss.is_stable(), true);
685+
assert!(ss.is_stable());
659686
}
660687
}

src/systems/polynom.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ where
6060

6161
let term_i = match exp {
6262
0 => val.to_string(),
63-
1 => format!("{}{}", val, var_name),
64-
_ => format!("{}{}^{}", val, var_name, exp),
63+
1 => format!("{val}{var_name}"),
64+
_ => format!("{val}{var_name}^{exp}"),
6565
};
6666
terms.push(term_i);
6767
}
@@ -76,7 +76,7 @@ where
7676
{
7777
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7878
let str_poly = self.to_string_variable("x");
79-
write!(f, "{}", str_poly)
79+
write!(f, "{str_poly}")
8080
}
8181
}
8282

@@ -353,11 +353,7 @@ where
353353
assert!(num_str.len() <= max_len);
354354
assert!(den_str.len() <= max_len);
355355

356-
write!(
357-
formatter,
358-
"\n {}\n {}\n {}\n\n",
359-
num_str, dash_line, den_str
360-
)
356+
write!(formatter, "\n {num_str}\n {dash_line}\n {den_str}\n\n")
361357
}
362358
}
363359

@@ -649,7 +645,7 @@ mod tests {
649645
lhs_vals
650646
.iter()
651647
.zip(rhs_vals.iter())
652-
.all(|(x, y)| f64::abs_diff_eq(&x, &y, epsilon))
648+
.all(|(x, y)| f64::abs_diff_eq(x, y, epsilon))
653649
}
654650
}
655651

@@ -712,9 +708,9 @@ mod tests {
712708
}
713709

714710
{
715-
println!("poly: {}", p);
711+
println!("poly: {p}");
716712
let p_str = p.to_string();
717-
println!("poly to string: {}", p_str);
713+
println!("poly to string: {p_str}");
718714
}
719715
}
720716

@@ -760,7 +756,7 @@ mod tests {
760756
assert_abs_diff_eq!(rf.num.coeffs[0], 1.0);
761757
assert_abs_diff_eq!(rf.num.coeffs.last().unwrap().clone(), 3.0);
762758

763-
println!("Rational function normalize: \n{}", rf);
759+
println!("Rational function normalize: \n{rf}");
764760
}
765761

766762
#[test]

src/systems/state_space.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ impl<U: Time + 'static> fmt::Display for Ss<U> {
612612
} else {
613613
"Unknown"
614614
};
615-
write!(f, "{}-time state-space model\n\n", time_domain)
615+
write!(f, "{time_domain}-time state-space model\n\n")
616616
}
617617
}
618618

@@ -635,7 +635,7 @@ mod tests {
635635
rng: &mut U,
636636
max_order: usize,
637637
) -> Tf<f64, Continuous> {
638-
let den_order = rng.random_range(1..=max_order) as usize;
638+
let den_order = rng.random_range(1..=max_order);
639639
let num_order = rng.random_range(0..=den_order);
640640

641641
let num: Vec<f64> = (0..=num_order)
@@ -884,14 +884,14 @@ mod tests {
884884
#[test]
885885
fn ss_display() {
886886
let sys = (1.0 / Tf::s()).to_ss().unwrap();
887-
println!("1: {}", sys);
887+
println!("1: {sys}");
888888

889889
let sys = Ss::<Discrete>::new_from_scalar(2.0);
890-
println!("2: {}", sys);
890+
println!("2: {sys}");
891891

892892
let sys = ((1.0 + Tf::s()) / ((Tf::s() - 1.0) * Tf::s()).powi(2))
893893
.to_ss()
894894
.unwrap();
895-
println!("3: {}after", sys);
895+
println!("3: {sys}after");
896896
}
897897
}

src/systems/transfer_function.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -497,10 +497,10 @@ mod tests {
497497
assert_abs_diff_eq!(y.re, y_expect.re);
498498
assert_abs_diff_eq!(y.im, y_expect.im);
499499
}
500-
println!("Tf cont: \n{}", tf);
500+
println!("Tf cont: \n{tf}");
501501

502502
let tf_z = Tf::<f64, Discrete>::new_from_rf(tf.rf);
503-
println!("Tf discrete: \n {}", tf_z);
503+
println!("Tf discrete: \n {tf_z}");
504504
}
505505

506506
#[test]
@@ -553,16 +553,16 @@ mod tests {
553553
Tf::<f64, Discrete>::new(&[0.0, 0., 0., 1., 2., 0.0], &[0.0, 1.]);
554554
assert_eq!(sys.degree_num_den(), (4, 1));
555555
assert_eq!(sys.relative_degree(), 4 - 1);
556-
assert_eq!(sys.is_proper(), false);
557-
assert_eq!(sys.is_strictly_proper(), false);
556+
assert!(!sys.is_proper());
557+
assert!(!sys.is_strictly_proper());
558558

559559
let sys = Tf::s() / Tf::s();
560-
assert_eq!(sys.is_proper(), true);
561-
assert_eq!(sys.is_strictly_proper(), false);
560+
assert!(sys.is_proper());
561+
assert!(!sys.is_strictly_proper());
562562

563563
let sys = 1. / Tf::s();
564-
assert_eq!(sys.is_proper(), true);
565-
assert_eq!(sys.is_strictly_proper(), true);
564+
assert!(sys.is_proper());
565+
assert!(sys.is_strictly_proper());
566566
}
567567

568568
#[test]
@@ -582,11 +582,11 @@ mod tests {
582582
#[test]
583583
fn tf_display() {
584584
let tf = 1.0 / Tf::s();
585-
println!("1: {}", tf);
585+
println!("1: {tf}");
586586
let tf = 1.0 / Tf::s().powi(5) * (Tf::s() + 1.0);
587-
println!("2: {}", tf);
587+
println!("2: {tf}");
588588
let tf =
589589
2.1 / Tf::s() * (Tf::s() - 1.2).powi(5) / (Tf::s() + 1.0).powi(3);
590-
println!("3: {}", tf);
590+
println!("3: {tf}");
591591
}
592592
}

0 commit comments

Comments
 (0)