mtx_row_apply_defaults( Args, Defs ) :- mtx_defaults( MtxOpts ), ( memberchk(out_is_mtx(false),Args) -> DefHdr = false ; DefHdr = true ), Defs = [out_is_mtx(true),out_has_header(DefHdr),on_header(false)|MtxOpts]. /** mtx_row_apply( +Goal, +MtxIn, -Out, +Opts ). Apply Goal to all rows of MtxIn to produce Out.
If MtxIn and MtxOut are files (ground atoms), the rows are processed on-the-fly with no
intermediate data structures being created. This reduces memory usage which
which used to be prohibitive when using csv_write_file/3 (that has been fixed, but it is more memory efficient to use the specialised version). Goal is called in user by default (use Mod:G, to overwrite this). Please note that Out would usually be another matrix, however, the predicate can also produce other outputs. You need to set _is_mtx(false)_ in this case, (note thaugh this will also (a) change the default of _Hdr_ to _false_ and (b) by pass calling mtx/2 on the output). Opts * in_MtxOpt(InpMtxOpt) any option you want to pass to the input mtx/3 call * on_header(OnH=false) do not apply Call on header row * out_has_header(Hdr=true) reply has header (default changes to _false_, if _IsMtx=false_) * out_is_mtx(IsMtx=true) set to false if output is not a matrix * out_MtxOpt(MtxOutOpt) any option you want to pass to the output mtx/3 call In addition you can give any option that you want to pass to both mtx/3 calls from those that are recognised by mtx/3 (see mtx_options_select/5). For example, _convert(true)_ will be passed to both mtx/3 calls, whereas _in_convert(true)_ will only be pased to the input call. == ?- mtx( data('mtcars.csv'), MtC ), mtx_row_apply( =, MtC, MtA, [] ). MtC = MtA, MtA = [row(mpg, cyl, disp, hp, drat, wt, qsec, vs, am, gear, carb), row('21.0', ...), ... ]. ?- mtx( data('mtcars.csv'), MtC ), mtx_row_apply( =, MtC, MtA, out_has_header(false) ). MtC = [row(mpg, cyl, disp, hp, drat, wt, qsec, vs, am, gear, carb), row(21.0, ...), ... ], MtA = [row('21.0', '6.0', '160.0', '110.0', '3.9', '2.62', '16.46', '0.0', '1.0', '4.0', '4.0'), ...]. ?- assert((sum_args(Term,Sum) :- Term=..[_|Args], sumlist(Args,Sum))). ?- sum_args( a(1,2,3), Sum ). Sum = 6. ?- mtx_row_apply(sum_args,data('mtcars.csv'),Sums,[convert(true),out_is_mtx(false)]). Sums = [328.97999999999996, 329.79499999999996, 259.58, ... ]. ?- tmp_file( mtcars_clone, TmpF ), mtx_row_apply( =, data('mtcars.csv', TmpF, [] ). == On *nix only: == ?- library(by_unix). ?- tmp_file( mtcars_clone, TmpF ), mtx_row_apply( =, data('mtcars.csv'), TmpF, [] ), @ head( -2, TmpF ). mpg,cyl,disp,hp,drat,wt,qsec,vs,am,gear,carb 21.0,6.0,160.0,110.0,3.9,2.62,16.46,0.0,1.0,4.0,4.0 TmpF = '/tmp/swipl_mtcars_clone_21824_1'. === @author nicos angelopoulos @version 0.1 2018/6/5 @version 0.2 2019/2/1, added support for non Mtx outputs: out_has_header() and out_is_mtx(). use mtx_otpions_select/5 @see mtx_bi_opts/2, mtx_options_select/5. */ mtx_row_apply( Goal, MtxIn, MtxOut, Args ) :- mtx_type( MtxIn, on_file(File) ), ground( MtxOut ), MtxOut \= [_|_], % fixme: should there be a new type: to_file(File)... ? !, options_append( mtx_row_apply, Args, Opts ), mtx_row_apply_files( Goal, File, MtxOut, Opts ). mtx_row_apply( GoalPrv, MtxIn, MtxOut, Args ) :- % the proto implemenation options_append( mtx_row_apply, Args, AllOpts ), mtx_options_select( AllOpts, in, InMtxOpts, NonInOpts ), mtx( MtxIn, Mtx, InMtxOpts ), mtx_options_select( NonInOpts, out, OutMtxOpts, Opts ), options( on_header(OnH), Opts ), ( GoalPrv = _:_ -> Goal = GoalPrv ; Goal= user:GoalPrv ), mtx_row_apply( OnH, Goal, Mtx, MtxForOutPrv, Opts ), options( out_has_header(OutHasHdr), Opts ), mtx_row_out_header( OutHasHdr, MtxForOutPrv, MtxForOut ), options( out_is_mtx(OutIsMtx), Opts ), mtx_row_out_mtx( OutIsMtx, MtxOut, MtxForOut, OutMtxOpts ). mtx_row_out_mtx( true, MtxOut, MtxForOut, Opts ) :- mtx( MtxOut, MtxForOut, Opts ). mtx_row_out_mtx( false, Out, Out, _Opts ). mtx_row_out_header( true, MtxForOut, MtxForOut ). mtx_row_out_header( false, [_|MtxForOut], MtxForOut ). mtx_row_apply( true, Goal, [Hdr|Rows], [NewHdr|NewRows], Opts ) :- call( Goal, Hdr, NewHdr ), mtx_by_row_apply( Rows, Goal, NewRows, Opts ). mtx_row_apply( false, Goal, [Hdr|Rows], [Hdr|NewRows], Opts ) :- mtx_by_row_apply( Rows, Goal, NewRows, Opts ). mtx_by_row_apply( [], _Goal, [], _Opts ). mtx_by_row_apply( [R|Rs], Goal, [N|Ns], Opts ) :- call( Goal, R, N ), mtx_by_row_apply( Rs, Goal, Ns, Opts ). mtx_row_apply_files( Goal, Fin, Fou, Opts ) :- mtx_bi_opts( Opts, Fin, Fou, InOpts, OuOpts ), csv_options( InComp, InOpts ), csv_options( OutComp, OuOpts ), setup_call_cleanup( ( open(Fin,read,InStream,[]), % use Opts ? open(Fou,write,OutStream,[]) ), ( csv_read_row(InStream, Row0, InComp), mtx_row_apply_streams( Row0, Goal, InStream, InComp, OutStream, OutComp ) ), ( close(InStream), close(OutStream) ) ). /* mtx_bi_opts( InOpts, Opts ) :- ( select_option(sep(InMtxSep),Opts,_Opts0) -> mtx_sep( InMtxSep, InSep ), InOpts1 = [separator(InSep)], ( select_option(out_sep(OutMtxSep),Opts) -> mtx_sep( OutMtxSep, OutSep ), OutOpts1 = [separator(OutSep)] ; OutOpts1 = [separator(InSep)] ) ; csv:default_separator( Fin, [], InOpts1 ) ( csv:default_separator( Fou, [], OutOpts1 ) ), select_option( match(InMatch), Opts, _ ), ( memberchk(out_match(OutMatch),Opts) -> true; OutMatch = InMatch ), InOpts2 = [match_arity(InMatch)|InOpts1], OutOpts2 = [match_arity(OutMatch)|OutOpts1], csv_options( InCompOpts, InOpts2 ), csv_options( OutCompOpts, OutOpts2 ), */ mtx_row_apply_streams( end_of_file, _Goal, _InStream, _InCompOpts, _OutStream, _OutCompOpts ) :- !. mtx_row_apply_streams( Row, Goal, InStream, InCompOpts, OutStream, OutCompOpts ) :- call( Goal, Row, New ), csv:csv_write_row( OutStream, OutCompOpts, New ), % fixeme: should be in interface of library(csv) csv_read_row( InStream, Next, InCompOpts ), mtx_row_apply_streams( Next, Goal, InStream, InCompOpts, OutStream, OutCompOpts ).