Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
ovo.ml
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
(**************************************************************************) (* *) (* This file is part of CAISAR. *) (* *) (* Copyright (C) 2022 *) (* CEA (Commissariat à l'énergie atomique et aux énergies *) (* alternatives) *) (* *) (* You can redistribute it and/or modify it under the terms of the GNU *) (* Lesser General Public License as published by the Free Software *) (* Foundation, version 2.1. *) (* *) (* It is distributed in the hope that it will be useful, *) (* but WITHOUT ANY WARRANTY; without even the implied warranty of *) (* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) (* GNU Lesser General Public License for more details. *) (* *) (* See the GNU Lesser General Public License version 2.1 *) (* for more details (enclosed in the file licenses/LGPLv2.1). *) (* *) (**************************************************************************) open Base module Format = Caml.Format module Sys = Caml.Sys module Filename = Caml.Filename module Fun = Caml.Fun type t = { n_inputs : int; n_outputs : int } (* OVO format handling. *) let ovo_format_error s = Error (Format.sprintf "OVO format error: %s condition not satisfied." s) (* Parse a single OVO format line: split line wrt CSV format, and convert each string into a number by means of converter [f]. *) let handle_ovo_line ~f in_channel = List.filter_map ~f:(fun s -> try Some (f (String.strip s)) with _ -> None) (Csv.next in_channel) (* Skip the header part, ie comments, of the OVO format. *) let skip_ovo_header filename in_channel = let exception End_of_header in let pos_in = ref (Stdlib.pos_in in_channel) in try while true do let line = Stdlib.input_line in_channel in if not (Str.string_match (Str.regexp "//") line 0) then raise End_of_header else pos_in := Stdlib.pos_in in_channel done; assert false with | End_of_header -> (* At this point we have read one line past the header part: seek back. *) Stdlib.seek_in in_channel !pos_in; Ok () | End_of_file -> Error (Format.sprintf "OVO model not found in file `%s'." filename) (* Retrieve inputs and outputs size. *) let handle_ovo_basic_info in_channel = match handle_ovo_line ~f:Int.of_string in_channel with | [ dim ] -> Ok dim | _ -> ovo_format_error "first" | exception End_of_file -> ovo_format_error "first" (* Skip unused flag. *) let handle_ovo_unused_flag in_channel = try let _ = Csv.next in_channel in Ok () with End_of_file -> ovo_format_error "second" (* Retrieves [filename] OVO model metadata and weights wrt OVO format specification, which is described here: https://github.com/abstract-machine-learning/saver#classifier-format. *) let parse_in_channel filename in_channel = let open Result in try skip_ovo_header filename in_channel >>= fun () -> let in_channel = Csv.of_channel in_channel in handle_ovo_unused_flag in_channel >>= fun () -> handle_ovo_basic_info in_channel >>= fun n_is -> handle_ovo_basic_info in_channel >>= fun n_os -> Csv.close_in in_channel; Ok { n_inputs = n_is; n_outputs = n_os } with | Csv.Failure (_nrecord, _nfield, msg) -> Error msg | Sys_error s -> Error s | Failure msg -> Error (Format.sprintf "Unexpected error: %s." msg) let parse filename = let in_channel = Stdlib.open_in filename in Fun.protect ~finally:(fun () -> Stdlib.close_in in_channel) (fun () -> parse_in_channel filename in_channel)