runmat_runtime/
indexing.rs1use runmat_builtins::{Tensor, Value};
6
7pub fn matrix_get_element(matrix: &Tensor, row: usize, col: usize) -> Result<f64, String> {
9 if row == 0 || col == 0 {
10 return Err("MATLAB uses 1-based indexing".to_string());
11 }
12 matrix.get2(row - 1, col - 1) }
14
15pub fn matrix_set_element(
17 matrix: &mut Tensor,
18 row: usize,
19 col: usize,
20 value: f64,
21) -> Result<(), String> {
22 if row == 0 || col == 0 {
23 return Err("The MATLAB language uses 1-based indexing".to_string());
24 }
25 matrix.set2(row - 1, col - 1, value) }
27
28pub fn matrix_get_row(matrix: &Tensor, row: usize) -> Result<Tensor, String> {
30 if row == 0 || row > matrix.rows() {
31 return Err(format!(
32 "Row index {} out of bounds for {}x{} matrix",
33 row,
34 matrix.rows(),
35 matrix.cols()
36 ));
37 }
38
39 let mut row_data = Vec::with_capacity(matrix.cols());
41 for c in 0..matrix.cols() {
42 row_data.push(matrix.data[(row - 1) + c * matrix.rows()]);
43 }
44 Tensor::new_2d(row_data, 1, matrix.cols())
45}
46
47pub fn matrix_get_col(matrix: &Tensor, col: usize) -> Result<Tensor, String> {
49 if col == 0 || col > matrix.cols() {
50 return Err(format!(
51 "Column index {} out of bounds for {}x{} matrix",
52 col,
53 matrix.rows(),
54 matrix.cols()
55 ));
56 }
57
58 let mut col_data = Vec::with_capacity(matrix.rows());
59 for row in 0..matrix.rows() {
60 col_data.push(matrix.data[row + (col - 1) * matrix.rows()]);
61 }
62 Tensor::new_2d(col_data, matrix.rows(), 1)
63}
64
65pub fn perform_indexing(base: &Value, indices: &[f64]) -> Result<Value, String> {
70 match base {
71 Value::Tensor(matrix) => {
72 if indices.is_empty() {
73 return Err("At least one index is required".to_string());
74 }
75
76 if indices.len() == 1 {
77 let idx = indices[0] as usize;
79 if idx < 1 || idx > matrix.data.len() {
80 return Err(format!(
81 "Index {} out of bounds (1 to {})",
82 idx,
83 matrix.data.len()
84 ));
85 }
86 Ok(Value::Num(matrix.data[idx - 1])) } else if indices.len() == 2 {
88 let row = indices[0] as usize;
90 let col = indices[1] as usize;
91
92 if row < 1 || row > matrix.rows {
93 return Err(format!(
94 "Row index {} out of bounds (1 to {})",
95 row, matrix.rows
96 ));
97 }
98 if col < 1 || col > matrix.cols {
99 return Err(format!(
100 "Column index {} out of bounds (1 to {})",
101 col, matrix.cols
102 ));
103 }
104
105 let linear_idx = (row - 1) + (col - 1) * matrix.rows; Ok(Value::Num(matrix.data[linear_idx]))
107 } else {
108 Err(format!(
109 "Matrices support 1 or 2 indices, got {}",
110 indices.len()
111 ))
112 }
113 }
114 Value::StringArray(sa) => {
115 if indices.is_empty() {
116 return Err("At least one index is required".to_string());
117 }
118 if indices.len() == 1 {
119 let idx = indices[0] as usize;
120 let total = sa.data.len();
121 if idx < 1 || idx > total {
122 return Err(format!("Index {idx} out of bounds (1 to {total})"));
123 }
124 Ok(Value::String(sa.data[idx - 1].clone()))
125 } else if indices.len() == 2 {
126 let row = indices[0] as usize;
127 let col = indices[1] as usize;
128 if row < 1 || row > sa.rows || col < 1 || col > sa.cols {
129 return Err("StringArray subscript out of bounds".to_string());
130 }
131 let idx = (row - 1) + (col - 1) * sa.rows;
132 Ok(Value::String(sa.data[idx].clone()))
133 } else {
134 Err(format!(
135 "StringArray supports 1 or 2 indices, got {}",
136 indices.len()
137 ))
138 }
139 }
140 Value::Num(_) | Value::Int(_) => {
141 if indices.len() == 1 && indices[0] == 1.0 {
142 Ok(base.clone())
144 } else {
145 Err("MATLAB:SliceNonTensor: Slicing only supported on tensors".to_string())
146 }
147 }
148 Value::Cell(ca) => {
149 if indices.is_empty() {
150 return Err("At least one index is required".to_string());
151 }
152 if indices.len() == 1 {
153 let idx = indices[0] as usize;
154 if idx < 1 || idx > ca.data.len() {
155 return Err(format!(
156 "Cell index {} out of bounds (1 to {})",
157 idx,
158 ca.data.len()
159 ));
160 }
161 Ok((*ca.data[idx - 1]).clone())
162 } else if indices.len() == 2 {
163 let row = indices[0] as usize;
164 let col = indices[1] as usize;
165 if row < 1 || row > ca.rows || col < 1 || col > ca.cols {
166 return Err("Cell subscript out of bounds".to_string());
167 }
168 Ok((*ca.data[(row - 1) * ca.cols + (col - 1)]).clone())
169 } else {
170 Err(format!(
171 "Cell arrays support 1 or 2 indices, got {}",
172 indices.len()
173 ))
174 }
175 }
176 _ => Err(format!("Cannot index value of type {base:?}")),
177 }
178}