rustml/octave.rs
1extern crate num;
2
3use std::fmt;
4use std::fs::File;
5use std::io::{Write, Result};
6use std::process::{Command, Output};
7use std::iter::Iterator;
8
9use matrix::Matrix;
10
11static DEFAULT_OCTAVE_BIN: &'static str = "octave";
12
13pub struct OctaveScriptBuilder {
14 buf: Vec<String>,
15 octave_bin: String
16}
17
18impl OctaveScriptBuilder {
19 /// Adds the string to the Octave script.
20 ///
21 /// At the end of the line a semicolon is appended.
22 pub fn add(&self, s: &str) -> OctaveScriptBuilder {
23
24 let mut buf = self.buf.clone();
25 buf.push(s.to_string());
26 OctaveScriptBuilder {
27 buf: buf,
28 octave_bin: self.octave_bin.clone()
29 }
30 }
31
32 fn join<T: fmt::Display>(&self, v: &[T]) -> String {
33
34 let mut s = String::new();
35
36 for (idx, val) in v.iter().enumerate() {
37 if idx > 0 {
38 s = s + ",";
39 }
40 s = s + &format!("{}", val);
41 }
42 s
43 }
44
45 fn to_vec<T: fmt::Display>(&self, v: &[T]) -> String {
46
47 "[".to_string() + &self.join(v) + "]"
48 }
49
50 /// Adds the string to the Octave script.
51 ///
52 /// At the end of the line a semicolon is appended.
53 ///
54 /// If the string contains a dollar sign followed by a number `i` (e.g. `$1` or `$12`)
55 /// this placeholder will be replaced by the column if matrix `m` at column
56 /// `i-1` (i.e. $1 is replaced by the first column of `m`).
57 ///
58 /// # Example
59 ///
60 /// ```
61 /// # #[macro_use] extern crate rustml;
62 /// use rustml::octave::*;
63 /// use rustml::matrix::Matrix;
64 ///
65 /// # pub fn main() {
66 /// let m = mat![
67 /// 1, 2, 3;
68 /// 4, 5, 6
69 /// ];
70 /// let s = builder().add_columns("x = $1; y = $2", &m);
71 /// assert_eq!(
72 /// s.to_string(),
73 /// "1;\nx = [1,4]; y = [2,5];\n"
74 /// );
75 /// # }
76 /// ```
77 pub fn add_columns<T: fmt::Display + Copy>(&self, s: &str, m: &Matrix<T>) -> OctaveScriptBuilder {
78
79 let mut t = s.to_string();
80 let n = m.cols();
81
82 for i in 0..n {
83 let p = format!("${}", i + 1);
84 let v = self.to_vec(&m.row_iter().map(|ref v| v[i]).collect::<Vec<T>>());
85 t = t.replace(&p, &v);
86 }
87 self.add(&t)
88 }
89
90 /// Adds the string to the Octave script.
91 ///
92 /// At the end of the line a semicolon is appended. If the string contains two
93 /// consecutive dollar signs (i.e. `$$`) these will be replaced by a vector
94 /// containing the elements of `vals`.
95 ///
96 /// # Example
97 ///
98 /// ```
99 /// # extern crate rustml;
100 /// use rustml::octave::*;
101 ///
102 /// # pub fn main() {
103 /// let s = builder().add_vector("x = $$", &[1, 2, 3]);
104 /// assert_eq!(
105 /// s.to_string(),
106 /// "1;\nx = [1,2,3];\n"
107 /// );
108 /// # }
109 /// ```
110 pub fn add_vector<T: fmt::Display>(&self, s: &str, vals: &[T]) -> OctaveScriptBuilder {
111
112 let mut t = s.to_string();
113 let v = self.to_vec(vals);
114 t = t.replace("$$", &v);
115 self.add(&t)
116 }
117
118 /// Adds the string to the Octave script.
119 ///
120 /// At the end of the line a semicolon is appended. If the string contains two
121 /// consecutive dollar signs (i.e. `$$`) these will be replaced by a vector
122 /// containing the elements of iterator `vals`.
123 ///
124 /// # Example
125 ///
126 /// ```
127 /// # extern crate rustml;
128 /// use rustml::octave::*;
129 ///
130 /// # pub fn main() {
131 /// let v = vec![1, 2, 3];
132 /// let s = builder().add_vector_iter("x = $$", v.iter());
133 /// assert_eq!(
134 /// s.to_string(),
135 /// "1;\nx = [1,2,3];\n"
136 /// );
137 /// # }
138 /// ```
139 pub fn add_vector_iter<T: fmt::Display, I: Iterator<Item = T>>(&self, s: &str, vals: I) -> OctaveScriptBuilder {
140
141 let v = vals.collect::<Vec<_>>();
142 self.add_vector(s, &v)
143 }
144
145 /// Adds the string to the Octave script.
146 ///
147 /// At the end of the line a semicolon is appended. If the string contains two
148 /// consecutive dollar signs (i.e. `$$`) these will be replaced by the matrix
149 /// `m`.
150 ///
151 /// # Example
152 ///
153 /// ```
154 /// # #[macro_use] extern crate rustml;
155 /// use rustml::octave::*;
156 /// use rustml::*;
157 ///
158 /// # pub fn main() {
159 /// let m = mat![1, 2, 3; 4, 5, 6];
160 /// let s = builder().add_matrix("x = $$", &m);
161 /// assert_eq!(
162 /// s.to_string(),
163 /// "1;\nx = [1,2,3;4,5,6];\n"
164 /// );
165 /// # }
166 /// ```
167 pub fn add_matrix<T: fmt::Display + Clone>(&self, t: &str, m: &Matrix<T>) -> OctaveScriptBuilder {
168
169 let mut s = "[".to_string();
170
171 for (idx, r) in m.row_iter().enumerate() {
172 if idx > 0 {
173 s = s + ";";
174 }
175 s = s + &self.join(&r);
176 }
177 s = s + "]";
178
179 self.add(&t.replace("$$", &s))
180 }
181
182 /// Adds the string to the Octave script.
183 ///
184 /// At the end of the line a semicolon is appended.
185 ///
186 /// If the string contains a dollar sign followed by a number `i` (e.g. `$1` or `$12`)
187 /// this placeholder will be replaced by the value that is stored in the vector
188 /// `vals` at index `i-1`.
189 ///
190 /// # Example
191 ///
192 /// ```
193 /// # extern crate rustml;
194 /// use rustml::octave::*;
195 ///
196 /// # pub fn main() {
197 /// let s = builder().add_values("x = $1 + $2", &[5, 3]);
198 /// assert_eq!(
199 /// s.to_string(),
200 /// "1;\nx = 5 + 3;\n"
201 /// );
202 /// # }
203 /// ```
204 pub fn add_values<T: fmt::Display>(&self, s: &str, vals: &[T]) -> OctaveScriptBuilder {
205
206 let mut t = s.to_string();
207 let n = vals.len();
208
209 for i in 0..n {
210 let p = format!("${}", i + 1);
211 let v = format!("{}", vals[i]);
212 t = t.replace(&p, &v);
213 }
214 self.add(&t)
215 }
216
217 pub fn octave_bin(&self, path: &str) -> OctaveScriptBuilder {
218 OctaveScriptBuilder {
219 buf: self.buf.clone(),
220 octave_bin: path.to_string()
221 }
222 }
223
224 pub fn to_string(&self) -> String {
225 let mut s = String::new();
226 s = s + "1;\n";
227 for j in &self.buf {
228 s = s + &j + ";\n";
229 }
230 s
231 }
232
233 pub fn write(&self, filename: &str) -> Result<()> {
234
235 match File::create(filename) {
236 Ok(mut f) => {
237 let data = self.to_string().into_bytes();
238 f.write_all(&data)
239 },
240 Err(e) => Err(e)
241 }
242 }
243
244 pub fn run(&self, filename: &str) -> Result<Output> {
245
246 match self.write(filename) {
247 Ok(_) => {
248 let mut c = self.octave_bin.clone();
249 c = c + " " + filename;
250
251 Command::new("sh")
252 .arg("-c")
253 .arg(c)
254 .output()
255 }
256 Err(e) => Err(e)
257 }
258 }
259}
260
261pub fn builder() -> OctaveScriptBuilder {
262 OctaveScriptBuilder {
263 buf: vec![],
264 octave_bin: DEFAULT_OCTAVE_BIN.to_string()
265 }
266}