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
/// MPSファイルのパース中に発生するエラー
#[non_exhaustive]
#[derive(Debug)]
pub enum MpsError {
/// ファイル読み込み時のI/Oエラー
IoError(std::io::Error),
/// 指定行のパースエラー(行番号とメッセージを含む)
ParseError { line: usize, message: String },
/// 必須セクションが欠落している
MissingSection(String),
/// 同じセクションが複数回出現した
DuplicateSection(String),
/// 無効な行タイプ文字が指定された
InvalidRowType(char),
/// 無効な上下限タイプ文字列が指定された
InvalidBoundType(String),
/// 未定義の行名または列名が参照された
UndefinedReference { kind: String, name: String },
/// INTORG マーカーが対応する INTEND で閉じられないまま COLUMNS を抜けた。
/// 残り全列が無警告で整数化されるのを防ぐため明示エラーとする。
UnclosedIntegerMarker,
}
impl std::fmt::Display for MpsError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MpsError::IoError(e) => write!(f, "I/O error: {}", e),
MpsError::ParseError { line, message } => {
write!(f, "Parse error at line {}: {}", line, message)
}
MpsError::MissingSection(s) => write!(f, "Missing required section: {}", s),
MpsError::DuplicateSection(s) => write!(f, "Duplicate section: {}", s),
MpsError::InvalidRowType(c) => write!(f, "Invalid row type: {}", c),
MpsError::InvalidBoundType(s) => write!(f, "Invalid bound type: {}", s),
MpsError::UndefinedReference { kind, name } => {
write!(f, "Undefined {} reference: {}", kind, name)
}
MpsError::UnclosedIntegerMarker => {
write!(
f,
"INTORG marker not closed by a matching INTEND in COLUMNS"
)
}
}
}
}
impl std::error::Error for MpsError {}
impl From<std::io::Error> for MpsError {
fn from(err: std::io::Error) -> Self {
MpsError::IoError(err)
}
}
/// ソルバー全体の統一エラー型
///
/// 入力検証・数値計算など、ソルバー操作中に発生しうるエラーを統一的に表現する。
///
/// 注意: Infeasible/Unbounded/MaxIterations は数学的結果であり、
/// エラーではないため [`SolveStatus`](crate::problem::SolveStatus) で表現する。
#[non_exhaustive]
#[derive(Debug)]
pub enum SolverError {
/// 次元不一致(配列長・行列サイズの不整合)
///
/// 例: `c.len() != a.ncols`, トリプレット配列の長さ不一致
DimensionMismatch {
/// どのフィールド/配列が不一致か(例: "c", "b", "triplet_arrays")
field: &'static str,
/// 期待されるサイズ
expected: usize,
/// 実際のサイズ
got: usize,
},
/// インデックスが有効範囲外
///
/// 例: 行列の列インデックス、基底列インデックス
IndexOutOfBounds {
/// どのインデックスか(例: "column", "row", "basis_column")
context: &'static str,
/// 範囲外のインデックス値
index: usize,
/// 上限値(0..bound が有効範囲)
bound: usize,
},
/// 基底行列が特異(LU分解で数値的に特異なピボットを検出)
SingularBasis {
/// 特異性が検出されたガウス消去のステップ番号
step: usize,
},
/// 空の入力が渡された
EmptyInput {
/// どの入力が空か(例: "basis")
context: &'static str,
},
/// Deadline を超過した(タイムアウト)
DeadlineExceeded,
/// 非有限係数(NaN または ±∞)が入力された
///
/// 例: `c[i]` が NaN、`b[j]` が Inf、行列要素が NaN
NonFiniteCoefficient {
/// どのフィールドか("c", "b", "A" など)
field: &'static str,
/// 最初に非有限値が検出されたインデックス
index: usize,
},
/// 変数境界が無効(NaN または lb > ub)
InvalidBounds {
/// 無効な境界を持つ変数のインデックス
index: usize,
/// 下限値
lb: f64,
/// 上限値
ub: f64,
},
}
impl std::fmt::Display for SolverError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SolverError::DimensionMismatch {
field,
expected,
got,
} => {
write!(
f,
"Dimension mismatch: {} expected {} but got {}",
field, expected, got
)
}
SolverError::IndexOutOfBounds {
context,
index,
bound,
} => {
write!(
f,
"{} index {} out of bounds (size={})",
context, index, bound
)
}
SolverError::SingularBasis { step } => {
write!(f, "Singular matrix detected at step {}", step)
}
SolverError::EmptyInput { context } => {
write!(f, "Empty input: {}", context)
}
SolverError::DeadlineExceeded => {
write!(f, "Deadline exceeded during computation")
}
SolverError::NonFiniteCoefficient { field, index } => {
write!(f, "Non-finite coefficient in {}: index {}", field, index)
}
SolverError::InvalidBounds { index, lb, ub } => {
write!(
f,
"Invalid bounds at index {}: lb={} > ub={} or NaN",
index, lb, ub
)
}
}
}
}
impl std::error::Error for SolverError {}