///|
fn nullable_number(value : Double?) -> Json {
match value {
None => Json::null()
Some(x) => @json.to_json(x)
}
}
///|
/// JSON trajectory interchange is a rectangular array of finite numeric arrays.
pub fn trajectory_json(text : String) -> Result[Trajectory, RqaError] {
if text.length() > 2097152 {
return Err(Limit("JSON text size"))
}
let json = @json.parse(text, max_nesting_depth=4, reject_duplicate_keys=true) catch {
_ => return Err(Invalid("trajectory JSON syntax/depth"))
}
let rows : Array[Array[Double]] = @json.from_json(json) catch {
_ => return Err(Invalid("trajectory JSON must be numeric rows"))
}
trajectory(rows)
}
///|
pub fn Trajectory::to_json(self : Trajectory) -> Json {
@json.to_json(self.rows())
}
///|
pub fn Recurrence::to_json(self : Recurrence) -> Json {
@json.to_json(self.rows())
}
///|
/// Stable named fields; undefined ratios/means become JSON null, never NaN.
pub fn RqaSummary::to_json(self : RqaSummary) -> Json {
Json::object({
"recurrent": @json.to_json(self.recurrent),
"eligible": @json.to_json(self.eligible),
"recurrence_rate": nullable_number(self.recurrence_rate),
"determinism": @json.to_json(self.determinism),
"laminarity": @json.to_json(self.laminarity),
"mean_diagonal": nullable_number(self.mean_diagonal),
"longest_diagonal": @json.to_json(self.longest_diagonal),
"divergence": nullable_number(self.divergence),
"diagonal_entropy": @json.to_json(self.diagonal_entropy),
"trapping_time": nullable_number(self.trapping_time),
"longest_vertical": @json.to_json(self.longest_vertical),
"vertical_entropy": @json.to_json(self.vertical_entropy),
"mean_return_gap": nullable_number(self.mean_return_gap),
})
}
///|
/// A report is explicit about the exclusion and line-length parameters used.
pub fn analysis_json(
t : Trajectory,
threshold : Double,
metric : Metric,
theiler : Int32,
minimum_diagonal : Int32,
minimum_vertical : Int32,
max_cells : Int32,
) -> Result[Json, RqaError] {
let r = match recurrence(t, threshold, metric, theiler, max_cells) {
Err(e) => return Err(e)
Ok(r) => r
}
let q = match r.quantify(minimum_diagonal, minimum_vertical) {
Err(e) => return Err(e)
Ok(q) => q
}
let name = match metric {
Chebyshev => "chebyshev"
Manhattan => "manhattan"
Euclidean => "euclidean"
}
Ok(
Json::object({
"schema": @json.to_json("moonrqa/1"),
"samples": @json.to_json(t.samples),
"dimensions": @json.to_json(t.dimensions),
"threshold": @json.to_json(threshold),
"metric": @json.to_json(name),
"theiler": @json.to_json(theiler),
"minimum_diagonal": @json.to_json(minimum_diagonal),
"minimum_vertical": @json.to_json(minimum_vertical),
"summary": q.to_json(),
}),
)
}