
CREATE SCHEMA _ifs;

CREATE TYPE _ifs.bool AS (
	mu double precision,
	nu double precision
);

CREATE FUNCTION _ifs.trunc_value(double precision) RETURNS double precision
    AS '
SELECT 
	CASE WHEN $1 > 1 THEN 1
	     WHEN $1 < 0 THEN 0
	     ELSE $1
	END
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.check_bool(double precision, double precision) RETURNS boolean
    AS '
SELECT $1 >= 0 AND $2 >= 0 AND $1 + $2 <= 1
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.get_mu(_ifs.bool) RETURNS double precision
    AS '
SELECT $1.mu AS mu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.get_nu(_ifs.bool) RETURNS double precision
    AS '
SELECT $1.nu AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.make_bool(boolean) RETURNS _ifs.bool
    AS '
SELECT 
	(CASE WHEN $1 THEN 1 ELSE 0 END)::double precision AS mu,
	(CASE WHEN $1 THEN 0 ELSE 1 END)::double precision AS nu;
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.make_bool(double precision, double precision) RETURNS _ifs.bool
    AS '
SELECT 
	CASE WHEN _ifs.check_bool ($1, $2) THEN $1
	     WHEN $1 = $2 THEN 0.5 
	     WHEN $1 > $2 THEN 1 
	     ELSE 0
	END AS mu,
	CASE WHEN _ifs.check_bool ($1, $2) THEN $2
	     WHEN $1 = $2 THEN 0.5 
	     WHEN $1 > $2 THEN 0
	     ELSE 1
	END AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.make_bool(_ifs.bool) RETURNS _ifs.bool
    AS '
SELECT
	_ifs.get_mu (_ifs.make_bool ($1.mu, $1.nu)) AS mu,
	_ifs.get_nu (_ifs.make_bool ($1.mu, $1.nu)) AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.min(double precision, double precision) RETURNS double precision
    AS '
SELECT CASE WHEN $1 < $2 THEN $1 ELSE $2 END AS retval
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.max(double precision, double precision) RETURNS double precision
    AS '
SELECT CASE WHEN $1 > $2 THEN $1 ELSE $2 END AS retval
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.ifnot(_ifs.bool) RETURNS _ifs.bool
    AS '
SELECT $1.nu AS mu, $1.mu AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.ifand(_ifs.bool, _ifs.bool) RETURNS _ifs.bool
    AS '
SELECT _ifs.min ($1.mu, $2.mu) AS mu, _ifs.max ($1.nu, $2.nu) AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.ifor(_ifs.bool, _ifs.bool) RETURNS _ifs.bool
    AS '
SELECT _ifs.max ($1.mu, $2.mu) AS mu, _ifs.min ($1.nu, $2.nu) AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.modif_nec(_ifs.bool) RETURNS _ifs.bool
    AS '
SELECT $1.mu AS mu, 1 - $1.mu AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.modif_poss(_ifs.bool) RETURNS _ifs.bool
    AS '
SELECT 1 - $1.nu AS mu, $1.nu AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.modif_d(_ifs.bool, double precision) RETURNS _ifs.bool
    AS '
SELECT $1.mu + (1 - $1.mu - $1.nu) * _ifs.trunc_value($2) AS mu
     , $1.nu + (1 - $1.mu - $1.nu) * (1 - _ifs.trunc_value($2)) AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.modif_f(_ifs.bool, double precision, double precision) RETURNS _ifs.bool
    AS '
SELECT $1.mu + (1 - $1.mu - $1.nu) *
        CASE WHEN _ifs.check_bool ($2, $3) THEN $2
             WHEN $2 = $3 THEN 0.5
             WHEN $2 > $3 THEN 1
             ELSE 0
        END AS mu
     , $1.nu + (1 - $1.mu - $1.nu) *
        CASE WHEN _ifs.check_bool ($2, $3) THEN $3
             WHEN $2 = $3 THEN 0.5
             WHEN $2 > $3 THEN 0
             ELSE 1
        END AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.modif_g(_ifs.bool, double precision, double precision) RETURNS _ifs.bool
    AS '
SELECT $1.mu * _ifs.trunc_value($2) AS mu
     , $1.nu * _ifs.trunc_value($3) AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.modif_h(_ifs.bool, double precision, double precision) RETURNS _ifs.bool
    AS '
SELECT $1.mu * _ifs.trunc_value($2) AS mu
     , $1.nu + (1 - $1.mu - $1.nu) * _ifs.trunc_value($3) AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.modif_hs(_ifs.bool, double precision, double precision) RETURNS _ifs.bool
    AS '
SELECT $1.mu * _ifs.trunc_value($2) AS mu
     , $1.nu + (1 - $1.mu * _ifs.trunc_value($2) - $1.nu) * _ifs.trunc_value($3) AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.modif_j(_ifs.bool, double precision, double precision) RETURNS _ifs.bool
    AS '
SELECT $1.mu + (1 - $1.mu - $1.nu) * _ifs.trunc_value($2) AS mu
     , $1.nu * _ifs.trunc_value($3) AS nu
'
    LANGUAGE sql STABLE STRICT;

CREATE FUNCTION _ifs.modif_js(_ifs.bool, double precision, double precision) RETURNS _ifs.bool
    AS '
SELECT $1.mu + (1 - $1.mu - $1.nu * _ifs.trunc_value($3)) * _ifs.trunc_value($2) AS mu
     , $1.nu * _ifs.trunc_value($3) AS nu
'
    LANGUAGE sql STABLE STRICT;
