123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899(**************************************************************************)(* *)(* This file is part of CAISAR. *)(* *)(* Copyright (C) 2023 *)(* 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). *)(* *)(**************************************************************************)openBasemoduleFormat=Stdlib.FormatmoduleSys=Stdlib.SysmoduleFilename=Stdlib.FilenamemoduleFun=Stdlib.Funtypet={n_inputs:int;n_outputs:int;}(* OVO format handling. *)letovo_format_errors=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]. *)lethandle_ovo_line~fin_channel=List.filter_map~f:(funs->trySome(f(String.strips))with_->None)(Csv.nextin_channel)(* Handle ovo first line: either 'ovo' or 'ovo x y' with 'x' and 'y' positive
integer numbers. *)lethandle_ovo_first_linein_channel=letovo_format_error_on_first_line=ovo_format_error"first line"inmatchCsv.nextin_channelwith|[first_line]->(letin_channel=Csv.of_string~separator:' 'first_lineinmatchCsv.nextin_channelwith|["ovo";n_is;n_os]->letn_is=Int.of_string(String.stripn_is)inletn_os=Int.of_string(String.stripn_os)inOk(Some(n_is,n_os))|["ovo"]->OkNone|_->ovo_format_error_on_first_line|exceptionEnd_of_file->ovo_format_error_on_first_line)|_->ovo_format_error_on_first_line|exceptionEnd_of_file->ovo_format_error_on_first_line(* Retrieve inputs and outputs size. *)lethandle_ovo_basic_info~descrin_channel=matchhandle_ovo_line~f:Int.of_stringin_channelwith|[dim]->Okdim|_->ovo_format_errordescr|exceptionEnd_of_file->ovo_format_errordescr(* Retrieves [filename] OVO model metadata and weights wrt OVO format
specification, which is described here:
https://github.com/abstract-machine-learning/saver#classifier-format. In
practice, the first line may specify the input/output size values or not. In
the latter case, we search for input/output size values in the second/third
lines respectively. *)letparse_in_channelin_channel=letopenResultintryletin_channel=Csv.of_channelin_channelin(handle_ovo_first_linein_channel>>=function|Some(n_is,n_os)->Ok(n_is,n_os)|None->handle_ovo_basic_info~descr:"input size"in_channel>>=funn_is->handle_ovo_basic_info~descr:"output size"in_channel>>=funn_os->Ok(n_is,n_os))>>=fun(n_is,n_os)->Csv.close_inin_channel;Ok{n_inputs=n_is;n_outputs=n_os}with|Csv.Failure(_nrecord,_nfield,msg)->Errormsg|Sys_errors->Errors|Failuremsg->Error(Format.sprintf"Unexpected error: %s."msg)letparsefilename=letin_channel=Stdlib.open_infilenameinFun.protect~finally:(fun()->Stdlib.close_inin_channel)(fun()->parse_in_channelin_channel)