:- lib(stoics_lib:op_compare/3). % :- debug( mtx_apply ). mtx_apply_defaults( Defs ) :- Defs = [ij_constraint(>:<),on_mtx(self),mtx_in_goal(false),default_value(undefined), has_header(true), row_start(top), mod(user) ]. /** mtx_apply( +Mtx, +Goal, -Res, +Opts ). Apply Goal to all non-header cells of Mtx to produce Res. Opts * default_value(DefV=undefined) use value(Val)=DefV when you want to set the elements that fail ij_constraint * has_header(HasH=true) see mtx_header_body/5. Header is removed before application and then added to Res (if exists). * ij_constraint(IJc=true) alternatives are any operator accepted by op_compare/3 (ground Op), with < meaning operate on (strict) upper matrix and >:< operate on all pairs * mod(Mod=user) module in which to call Goal * mtx_in_goal(MinG=false) whether to pass scaffold to Goal call. If _true_ call is call(Gname,Scf,I,J,Elem|Gargs,NtxScf), else it is call(Gname,Elem|Gargs,OutElem) * on_mtx(OnMtx=self) scaffold matrix for results. _self_ means use Mtx itself * row_start(Rst=top) set to bottom for upward looking ij_constraints == ?- Mtx = [row(a,b,c),row(1,2,3),row(4,5,6),row(7,8,9)], assert( a_mtx(Mtx) ). ?- a_mtx( Amtx ), mtx_apply( Amtx, plus(1), Bmtx, true ). Bmtx = [row(a, b, c), row(2, 3, 4), row(5, 6, 7), row(8, 9, 10)]. ?- a_mtx( Amtx ), mtx_apply( Amtx, plus(1), Bmtx, ij_constraint(<) ). Bmtx = [row(a, b, c), row(1, 3, 4), row(4, 5, 7), row(7, 8, 9)]. ?- a_mtx( Amtx ), mtx_apply( Amtx, plus(1), Bmtx, [ij_constraint(=<),default_value(0),row_start(bottom)] ). Bmtx = [row(a, b, c), row(0, 0, 4), row(0, 6, 7), row(8, 9, 10)]. ?- a_mtx( Amtx ), mtx_apply( Amtx, plus(1), Bmtx, [ij_constraint(=<),default_value(0),row_start(top)] ). Bmtx = [row(a, b, c), row(2, 3, 4), row(0, 6, 7), row(0, 0, 10)]. ?- a_mtx( Amtx ), mtx_apply( Amtx, plus(1), Bmtx, [ij_constraint(=<),default_value(0),row_start(top)] ). Bmtx = [row(a, b, c), row(0, 3, 4), row(0, 0, 7), row(0, 0, 0)]. == @author nicos angelopoulos @version 0.1 2016/2/17 */ mtx_apply( Mtx, Goal, Res, Args ) :- options_append( mtx_apply, Args, Opts ), mtx_header_body( Mtx, Header, Body, HasH, Opts ), options( ij_constraint(IJc), Opts ), options( mtx_in_goal(MiG), Opts ), mtx_apply_def( Def, Opts ), mtx_apply_on( Mtx, OnMtx, Opts ), Goal =.. [Gn|Gas], mtx_dims( Body, NRs, NCs ), options( row_start(Rst), Opts ), mtx_apply_row_start( Rst, NRs, I, It ), options( mod(Mod), Opts ), mtx_apply( I, 1, It, NRs, NCs, IJc, Body, Mod/Gn/Gas/Def, MiG, OnMtx, ResBody ), mtx_has_header_add( HasH, Header, ResBody, Res ). mtx_apply_row_start( top, NRs, 1, it(+,=<,NRs) ). mtx_apply_row_start( bottom, NRs, NRs, it(-,>,0) ). mtx_apply( I, J, It, Rs, NCs, IJc, Mtx, GTerm, MiG, OnMtx, ResBody ) :- It = it(IncOp,TermOp,TermVal), debug( mtx_apply, 'i: ~w', [I] ), % I =< Rs, op_compare( TermOp, I, TermVal ), !, Mtx = [Row|Rows], Row =.. [Rn|Rvals], mtx_in_goal_row( MiG, OnMtx, ResRow, OnRows, ResRows, ResBody ), mtx_apply_row( J, I, NCs, IJc, Rvals, GTerm, MiG, OnMtx, ResRowVals ), mtx_apply_row_pack( MiG, ResRowVals, Rn, ResRow ), % Iinc is I + 1, Expr =.. [IncOp,I, 1], call( is, NxtI, Expr ), mtx_apply( NxtI, J, It, Rs, NCs, IJc, Rows, GTerm, MiG, OnRows, ResRows ). mtx_apply( _I, _J, _It, _Rs, _NCs, _IJc, _Mtx, _GTerm, MiG, OnMtx, ResBody ) :- debug( mtx_apply, 'done Is', [] ), mtx_apply_row_close( MiG, OnMtx, ResBody ). % body_close, but would be identical anyways mtx_apply_row( J, I, NCs, IJc, Row, GTerm, MiG, OnMtx, ResRow ) :- debug( mtx_apply, 'j: ~w', [J] ), J =< NCs, op_compare( IJc, I, J ), !, GTerm = Mod/Gn/Gas/_Def, Row = [Elem|Tow], mtx_apply_goal_term( MiG, Mod, Gn, Gas, Elem, OnMtx, I, J, ResRow, NxtMtx, RemRow ), Jinc is J + 1, mtx_apply_row( Jinc, I, NCs, IJc, Tow, GTerm, MiG, NxtMtx, RemRow ). mtx_apply_row( J, I, NCs, IJc, Row, GTerm, MiG, OnMtx, ResRow ) :- J =< NCs, !, % we are in defaults situation here GTerm = _Mod/_Gn/_Gas/Def, Row = [Elem|Tow], ( Def=='$undefined' -> DefElem = Elem; DefElem = Def ), mtx_apply_add_default( MiG, OnMtx, I, J, DefElem, ResRow, NxtMtx, RemRow ), Jinc is J + 1, mtx_apply_row( Jinc, I, NCs, IJc, Tow, GTerm, MiG, NxtMtx, RemRow ). mtx_apply_row( _J, _I, _NCs, _IJc, [], _GTerm, MiG, OnMtx, ResRow ) :- mtx_apply_row_close( MiG, OnMtx, ResRow ). mtx_apply_row_pack( true, Res, _Rn, Res ). mtx_apply_row_pack( false, ResVals, Rn, ResRow ) :- ResRow =.. [Rn|ResVals]. mtx_apply_row_close( false, _OnMtx, [] ). mtx_apply_row_close( true, OnMtx, OnMtx ). mtx_apply_goal_term( false, Mod, Gn, Gas, Elem, OnMtx, _I, _J, ResRow, NxtMtx, RemRow ) :- append( [Elem|Gas], [OutElem], Args ), Call =.. [Gn|Args], call( Mod:Call ), ResRow = [OutElem|RemRow], NxtMtx = OnMtx. mtx_apply_goal_term( true, Mod, Gn, Gas, Elem, OnMtx, I, J, ResRow, NxtMtx, RemRow ) :- append( [OnMtx,I,J,Elem|Gas], NxtMtx, Args ), Call =.. [Gn|Args], call( Mod:Call ), RemRow = ResRow. mtx_apply_add_default( false, OnMtx, _I, _J, Val, [Val|RemRow], OnMtx, RemRow ). mtx_apply_add_default( true, OnMtx, I, J, Val, Mtx, NxtMtx, Mtx ) :- mtx_pos_elem( OnMtx, I, J, Val, NxtMtx ). mtx_in_goal_row( true, _OnMtx, ResRow, ResRow, ResRows, ResRows ). mtx_in_goal_row( false, OnMtx, ResRow, OnMtx, ResRows, [ResRow|ResRows] ). mtx_apply_on( Mtx, OnMtx, Opts ) :- options( on_mtx(self), Opts ), !, OnMtx = Mtx. mtx_apply_on( _Mtx, OnMtx, Opts ) :- options( on_mtx(OnMtx), Opts ). mtx_apply_def( Def, Opts ) :- options( default_value(DefT), Opts ), mtx_apply_def_value( DefT, Def ). mtx_apply_def_value( undefined, '$undefined' ) :- !. mtx_apply_def_value( value(Val), Val ) :- !. mtx_apply_def_value( Val, Val ).