TPTP Axioms File: TIM001_0.ax


%------------------------------------------------------------------------------
% File     : TIM001_0 : TPTP v9.3.1. Released v9.3.0.
% Domain   : Time
% Axioms   : Stanica computation axioms
% Version  : [PS26] axioms : Especial.
% English  : 

% Refs     : [PS26]  Pease & Stanica (2026), Email to Geoff Sutcliffe
% Source   : [PS26]
% Names    :

% Status   : Satisfiable
% Syntax   : Number of formulae    :  112 (  51 unt;  25 typ;   0 def)
%            Number of atoms       :  225 (  51 equ)
%            Maximal formula atoms :   12 (   2 avg)
%            Number of connectives :  152 (  14   ~;   6   |;  77   &)
%                                         (   3 <=>;  52  =>;   0  <=;   0 <~>)
%            Maximal formula depth :   23 (   4 avg)
%            Maximal term depth    :    7 (   1 avg)
%            Number arithmetic     :  602 (  44 atm; 107 fun; 314 num; 137 var)
%            Number of types       :    5 (   3 usr;   1 ari;   0 dat;   0 cdt)
%            Number of type conns  :   55 (  15   >;  40   *;   0   +;   0  <<)
%            Number of predicates  :   17 (  13 usr;   0 prp; 1-9 aty)
%            Number of functors    :   65 (   9 usr;  57 con; 0-5 aty)
%            Number of variables   :  167 ( 167   !;   0   ?; 167   :)
% SPC      : TF0_SAT_EQU_ARI_NDT

% Comments : VAMPIRE UNIVERSAL SYSTEM: DATES + TIME + SCHEDULER
%            OPTIMIZATION NOTE:
%            1. Quad/Decade/Century Years Accelerators:
%               Jump 1,461 days (4 years), 3,652 days (10 years), 36,524 days 
%               (one century) in one step.
%            2. Leap Chain Hint: Allows the solver to chain these jumps 
%               instantly.
%            3. Integer Trap: forces the prover to give an integer answer
%            4. Bridge Strategy: Uses intermediate hints to bridge the gap 
%               between mathematically safe thresholds and optimal search 
%               paths.
%------------------------------------------------------------------------------
%----TYPES
tff(t_date,type,
    date: $tType ).

tff(t_ymd,type,
    ymd: ( $int * $int * $int ) > date ).

tff(t_time,type,
    time: $tType ).

tff(t_dt,type,
    dt: ( $int * $int * $int * $int * $int ) > time ).

tff(t_dname,type,
    day_name: $tType ).

tff(dn_sun,type,
    sunday: day_name ).

tff(dn_mon,type,
    monday: day_name ).

tff(dn_tue,type,
    tuesday: day_name ).

tff(dn_wed,type,
    wednesday: day_name ).

tff(dn_thu,type,
    thursday: day_name ).

tff(dn_fri,type,
    friday: day_name ).

tff(dn_sat,type,
    saturday: day_name ).

%----PREDICATES
tff(pred_def_is_leap_year,type,
    is_leap_year: $int > $o ).

tff(t_dim,type,
    is_days_in_month: ( $int * $int * $int ) > $o ).

tff(t_diy,type,
    is_days_in_year: ( $int * $int ) > $o ).

tff(t_calc,type,
    calc_date: ( $int * $int * $int * date ) > $o ).

tff(t_calct,type,
    calc_datetime: ( $int * $int * $int * $int * $int * $int * $int * $int * time ) > $o ).

tff(t_timeop,type,
    normalize_time: ( $int * $int * $int * $int * $int * $int * $int ) > $o ).

tff(t_wk,type,
    weekday: ( date * day_name ) > $o ).

tff(t_zel,type,
    zeller_prep: ( $int * $int * $int * $int * $int * $int ) > $o ).

tff(t_map,type,
    map_iso: ( $int * day_name ) > $o ).

tff(t_mapn,type,
    map_name_to_int: ( day_name * $int ) > $o ).

tff(t_sch,type,
    nth_weekday_date: ( $int * day_name * $int * $int * date ) > $o ).

tff(t_sch_h,type,
    calc_nth_offset: ( $int * $int * $int ) > $o ).

%----TRAP & HINTS
tff(t_trap,type,
    valid_day: $int > $o ).

tff(trap_ax,axiom,
    ! [D: $int] :
      ( valid_day(D)
    <=> ( $greater(D,0)
        & $lesseq(D,31) ) ) ).

%==============================================================================
%---- CALENDAR ANCHORS
%==============================================================================
tff(anchor_2024_jan1,axiom,
    weekday(ymd(2024,1,1),monday) ).

tff(anchor_2024_feb1,axiom,
    weekday(ymd(2024,2,1),thursday) ).

tff(anchor_2024_mar1,axiom,
    weekday(ymd(2024,3,1),friday) ).

tff(anchor_2024_apr1,axiom,
    weekday(ymd(2024,4,1),monday) ).

tff(anchor_2024_may1,axiom,
    weekday(ymd(2024,5,1),wednesday) ).

tff(anchor_2025_jan1,axiom,
    weekday(ymd(2025,1,1),wednesday) ).

tff(anchor_2025_feb1,axiom,
    weekday(ymd(2025,2,1),saturday) ).

tff(anchor_2025_mar1,axiom,
    weekday(ymd(2025,3,1),saturday) ).

tff(anchor_2025_nov1,axiom,
    weekday(ymd(2025,11,1),saturday) ).

tff(anchor_1776_jan1,axiom,
    weekday(ymd(1776,1,1),monday) ).

tff(anchor_1969_jan1,axiom,
    weekday(ymd(1969,1,1),wednesday) ).

tff(anchor_1985_jan1,axiom,
    weekday(ymd(1985,1,1),tuesday) ).

tff(anchor_1600_jan1,axiom,
    weekday(ymd(1600,1,1),saturday) ).

%==============================================================================
%---- ARITHMETIC LEMMAS
%==============================================================================
tff(lemma_boundary_leap_mar0,axiom,
    calc_date(0,3,2024,ymd(2024,2,29)) ).

tff(lemma_boundary_norm_mar0,axiom,
    calc_date(0,3,2025,ymd(2025,2,28)) ).

tff(lemma_boundary_jan0_2025,axiom,
    calc_date(0,1,2025,ymd(2024,12,31)) ).

tff(lemma_boundary_jan0_2024,axiom,
    calc_date(0,1,2024,ymd(2023,12,31)) ).

tff(lemma_boundary_dec32,axiom,
    calc_date(32,12,2024,ymd(2025,1,1)) ).

%==============================================================================
%---- ENGINES
%==============================================================================

%----TIME ENGINE
tff(time_logic,axiom,
    ! [SH: $int,SM: $int,AH: $int,AM: $int,EH: $int,EM: $int,DD: $int,TotalM: $int,NormM: $int,CarryH: $int,TotalH: $int] :
      ( ( ( TotalM = $sum(SM,AM) )
        & ( NormM = $remainder_e(TotalM,60) )
        & ( CarryH = $quotient_e(TotalM,60) )
        & ( TotalH = $sum(SH,$sum(AH,CarryH)) )
        & ( EH = $remainder_e(TotalH,24) )
        & ( EM = NormM )
        & ( DD = $quotient_e(TotalH,24) ) )
     => normalize_time(SH,SM,AH,AM,EH,EM,DD) ) ).

tff(dt_logic,axiom,
    ! [Y: $int,M: $int,D: $int,H: $int,Min: $int,AD: $int,AH: $int,AM: $int,ResY: $int,ResM: $int,ResD: $int,ResH: $int,ResMin: $int,TimeDayDelta: $int] :
      ( ( normalize_time(H,Min,AH,AM,ResH,ResMin,TimeDayDelta)
        & calc_date($sum(D,$sum(AD,TimeDayDelta)),M,Y,ymd(ResY,ResM,ResD)) )
     => calc_datetime(Y,M,D,H,Min,AD,AH,AM,dt(ResY,ResM,ResD,ResH,ResMin)) ) ).

%----ACCELERATOR: 400-Year Cycle
tff(rule_fwd_400yr_cycle,axiom,
    ! [D: $int,M: $int,Y: $int,Res: date] :
      ( ( ( M = 1 )
        & $greater(D,146097)
        & $greater(D,200) )
     => ( calc_date($difference(D,146097),1,$sum(Y,400),Res)
       => calc_date(D,M,Y,Res) ) ) ).

%============================================================================
%----Backward acceleration hints (added): 400-year / 100-year / 10-year
%----These are guarded, implication-chained hints mirroring the forward accelerators.
%============================================================================

%----ACCELERATOR (HINT): Backward 400-Year Cycle (Gregorian periodicity)
tff(rule_back_400yr_cycle,axiom,
    ! [D: $int,M: $int,Y: $int,Res: date] :
      ( ( ( M = 1 )
        & $lesseq(D,$uminus(146097)) )
     => ( calc_date($sum(D,146097),1,$difference(Y,400),Res)
       => calc_date(D,M,Y,Res) ) ) ).

%----ACCELERATOR (HINT): Backward Century
tff(rule_back_century,axiom,
    ! [D: $int,M: $int,Y: $int,Res: date] :
      ( ( ( M = 1 )
        & $lesseq(D,$uminus(36524)) )
     => ( calc_date($sum(D,36524),1,$difference(Y,100),Res)
       => calc_date(D,M,Y,Res) ) ) ).

%----ACCELERATOR (HINT): Backward Decade (short)
tff(rule_back_10year_short,axiom,
    ! [D: $int,M: $int,Y: $int,Res: date] :
      ( ( ( M = 1 )
        & $lesseq(D,$uminus(3652))
        & ( ( $remainder_e($difference(Y,10),4) = 1 )
          | ( $remainder_e($difference(Y,10),4) = 2 ) ) )
     => ( calc_date($sum(D,3652),1,$difference(Y,10),Res)
       => calc_date(D,M,Y,Res) ) ) ).

%----ACCELERATOR (HINT): Backward Decade (long)
tff(rule_back_10year_long,axiom,
    ! [D: $int,M: $int,Y: $int,Res: date] :
      ( ( ( M = 1 )
        & $lesseq(D,$uminus(3653))
        & ( ( $remainder_e($difference(Y,10),4) = 0 )
          | ( $remainder_e($difference(Y,10),4) = 3 ) ) )
     => ( calc_date($sum(D,3653),1,$difference(Y,10),Res)
       => calc_date(D,M,Y,Res) ) ) ).

%----ACCELERATOR: Safe 4-Year Cycle
tff(rule_fwd_safe_4yr_gen,axiom,
    ! [D: $int,M: $int,Y: $int,Res: date] :
      ( ( ( M = 1 )
        & $greater(D,1461)
        & $greater(D,200)
        & $greater(Y,2000)
        & $less(Y,2095) )
     => ( calc_date($difference(D,1461),1,$sum(Y,4),Res)
       => calc_date(D,M,Y,Res) ) ) ).

%----NEW: THE "MONTH HOPPER" (Fixes 1776 without Zeller)
tff(rule_weekday_month_jump,axiom,
    ! [Y: $int,M: $int,W_Name: day_name,W_Int: $int,DaysInM: $int,NextW_Int: $int,NextW_Name: day_name] :
      ( ( weekday(ymd(Y,M,1),W_Name)
        & is_days_in_month(M,Y,DaysInM)
        & map_name_to_int(W_Name,W_Int)
        & ( NextW_Int = $remainder_e($sum(W_Int,DaysInM),7) )
        & map_iso(NextW_Int,NextW_Name) )
     => weekday(ymd(Y,$sum(M,1),1),NextW_Name) ) ).

tff(rule_fwd_century,axiom,
    ! [D: $int,M: $int,Y: $int,Res: date] :
      ( ( ( M = 1 )
        & $greater(D,36524)
        & $greater(D,200) )
     => ( calc_date($difference(D,36524),1,$sum(Y,100),Res)
       => calc_date(D,M,Y,Res) ) ) ).

tff(hint_century_threshold_100k,axiom,
    ! [D: $int] :
      ( $greater(D,100000)
     => $greater(D,36524) ) ).

%----Bridge Strategies
tff(hint_century_multi_bridge,axiom,
    ! [D: $int] :
      ( $greater(D,400000)
     => $greater($difference(D,365240),3652) ) ).

tff(hint_century_to_decade_bridge,axiom,
    ! [D: $int] :
      ( $greater(D,40000)
     => $greater($difference(D,36524),1461) ) ).

tff(hint_century_back_bridge,axiom,
    ! [D: $int] :
      ( $less(D,-41000)
     => $less($sum(D,36524),-3652) ) ).

%----Date Rules
tff(rule_fwd_10year_long,axiom,
    ! [D: $int,M: $int,Y: $int,Res: date] :
      ( ( ( M = 1 )
        & $greater(D,3653)
        & $greater(D,200)
        & ( ( $remainder_e(Y,4) = 0 )
          | ( $remainder_e(Y,4) = 3 ) ) )
     => ( calc_date($difference(D,3653),1,$sum(Y,10),Res)
       => calc_date(D,M,Y,Res) ) ) ).

tff(rule_fwd_4year,axiom,
    ! [D: $int,M: $int,Y: $int,Res: date] :
      ( ( ( M = 1 )
        & $greater(D,1461)
        & $greater(D,200)
        & ( $remainder_e(Y,4) = 0 ) )
     => ( calc_date($difference(D,1461),1,$sum(Y,4),Res)
       => calc_date(D,M,Y,Res) ) ) ).

tff(rule_fwd_year,axiom,
    ! [D: $int,M: $int,Y: $int,Limit: $int,Res: date] :
      ( ( ( M = 1 )
        & is_days_in_year(Y,Limit)
        & $greater(D,Limit)
        & $greater(D,200) )
     => ( calc_date($difference(D,Limit),1,$sum(Y,1),Res)
       => calc_date(D,M,Y,Res) ) ) ).

%----These have no impact
%----Activation Priorities
%tff(activate_century,axiom,
%    rule_fwd_century ).
%
%tff(activate_quad,axiom,
%    rule_fwd_4year ).
%
%tff(activate_year,axiom,
%    rule_fwd_year ).

%----DATE ENGINE
tff(m1,axiom,
    ! [Y: $int] : is_days_in_month(1,Y,31) ).

tff(m2,axiom,
    ! [Y: $int] :
      ( ( ( ( $remainder_e(Y,4) = 0 )
          & ( ( $remainder_e(Y,100) != 0 )
            | ( $remainder_e(Y,400) = 0 ) ) )
       => is_days_in_month(2,Y,29) )
      & ( ( ( $remainder_e(Y,4) != 0 )
          | ( ( $remainder_e(Y,100) = 0 )
            & ( $remainder_e(Y,400) != 0 ) ) )
       => is_days_in_month(2,Y,28) ) ) ).

tff(m3,axiom,
    ! [Y: $int] : is_days_in_month(3,Y,31) ).

tff(m4,axiom,
    ! [Y: $int] : is_days_in_month(4,Y,30) ).

tff(m5,axiom,
    ! [Y: $int] : is_days_in_month(5,Y,31) ).

tff(m6,axiom,
    ! [Y: $int] : is_days_in_month(6,Y,30) ).

tff(m7,axiom,
    ! [Y: $int] : is_days_in_month(7,Y,31) ).

tff(m8,axiom,
    ! [Y: $int] : is_days_in_month(8,Y,31) ).

tff(m9,axiom,
    ! [Y: $int] : is_days_in_month(9,Y,30) ).

tff(m10,axiom,
    ! [Y: $int] : is_days_in_month(10,Y,31) ).

tff(m11,axiom,
    ! [Y: $int] : is_days_in_month(11,Y,30) ).

tff(m12,axiom,
    ! [Y: $int] : is_days_in_month(12,Y,31) ).

tff(rule_base,axiom,
    ! [D: $int,M: $int,Y: $int,Limit: $int] :
      ( ( is_days_in_month(M,Y,Limit)
        & $greater(D,0)
        & $lesseq(D,Limit) )
     => calc_date(D,M,Y,ymd(Y,M,D)) ) ).

tff(rule_fwd_std,axiom,
    ! [D: $int,M: $int,Y: $int,Limit: $int,Res: date] :
      ( ( is_days_in_month(M,Y,Limit)
        & $greater(D,Limit)
        & ( M != 12 ) )
     => ( calc_date($difference(D,Limit),$sum(M,1),Y,Res)
       => calc_date(D,M,Y,Res) ) ) ).

tff(rule_fwd_dec,axiom,
    ! [D: $int,M: $int,Y: $int,Limit: $int,Res: date] :
      ( ( is_days_in_month(M,Y,Limit)
        & $greater(D,Limit)
        & ( M = 12 ) )
     => ( calc_date($difference(D,Limit),1,$sum(Y,1),Res)
       => calc_date(D,M,Y,Res) ) ) ).

tff(rule_back_std,axiom,
    ! [D: $int,M: $int,Y: $int,Limit: $int,Res: date] :
      ( ( $lesseq(D,0)
        & ( M != 1 ) )
     => ( ( is_days_in_month($difference(M,1),Y,Limit)
          & calc_date($sum(D,Limit),$difference(M,1),Y,Res) )
       => calc_date(D,M,Y,Res) ) ) ).

tff(rule_back_jan,axiom,
    ! [D: $int,M: $int,Y: $int,Limit: $int,Res: date] :
      ( ( $lesseq(D,0)
        & ( M = 1 ) )
     => ( ( is_days_in_month(12,$difference(Y,1),Limit)
          & calc_date($sum(D,Limit),12,$difference(Y,1),Res) )
       => calc_date(D,M,Y,Res) ) ) ).

%----SCHEDULER ENGINE
tff(map_n_0,axiom,
    map_name_to_int(saturday,0) ).

tff(map_n_1,axiom,
    map_name_to_int(sunday,1) ).

tff(map_n_2,axiom,
    map_name_to_int(monday,2) ).

tff(map_n_3,axiom,
    map_name_to_int(tuesday,3) ).

tff(map_n_4,axiom,
    map_name_to_int(wednesday,4) ).

tff(map_n_5,axiom,
    map_name_to_int(thursday,5) ).

tff(map_n_6,axiom,
    map_name_to_int(friday,6) ).

%============================================================================
%----Scheduler: deterministic offset definition (portfolio v4)
%----Replaces broad sch_offset_* implications by a guarded equivalence using modulo.
%----This avoids creating offsets outside 0..6 for non-weekday integers and reduces
%----saturation in scheduler proofs.
%============================================================================

tff(calc_nth_offset_def_mod7,axiom,
    ! [S: $int,T: $int,O: $int] :
      ( calc_nth_offset(S,T,O)
    <=> ( $lesseq(0,S)
        & $lesseq(S,6)
        & $lesseq(0,T)
        & $lesseq(T,6)
        & $lesseq(0,O)
        & $lesseq(O,6)
        & ( O = $remainder_e($sum($difference(T,S),7),7) ) ) ) ).

tff(nth_weekday_logic,axiom,
    ! [N: $int,DName: day_name,M: $int,Y: $int,StartDayName: day_name,StartDayInt: $int,TargetDayInt: $int,Offset: $int,FinalDay: $int] :
      ( ( weekday(ymd(Y,M,1),StartDayName)
        & map_name_to_int(StartDayName,StartDayInt)
        & map_name_to_int(DName,TargetDayInt)
        & calc_nth_offset(StartDayInt,TargetDayInt,Offset)
        & ( FinalDay = $sum(1,$sum(Offset,$product($difference(N,1),7))) ) )
     => nth_weekday_date(N,DName,M,Y,ymd(Y,M,FinalDay)) ) ).

%============================================================================
%----Scheduler stabilization patch (added)
%----Purpose: prevent saturation in nth_weekday_date goals by enforcing functionality
%----and bounding the offset computation.
%============================================================================

%----weekday is functional: a date has at most one day_name
tff(weekday_functional,axiom,
    ! [Dt: date,N1: day_name,N2: day_name] :
      ( ( weekday(Dt,N1)
        & weekday(Dt,N2) )
     => ( N1 = N2 ) ) ).

%----map_name_to_int is functional: a day_name maps to a unique integer
tff(map_name_to_int_functional,axiom,
    ! [Nm: day_name,I1: $int,I2: $int] :
      ( ( map_name_to_int(Nm,I1)
        & map_name_to_int(Nm,I2) )
     => ( I1 = I2 ) ) ).

%----ZELLER'S CONGRUENCE (Strictly Guarded - SYNTAX FIX)
%----Uses negation "~ (Y = 2024)" to avoid parsing errors with "!=" or "$distinct"
tff(zeller_adj_janfeb,axiom,
    ! [M: $int,Y: $int] :
      ( ( ( M = 1 )
        | ( M = 2 ) )
     => zeller_prep(M,Y,$sum(M,12),$difference(Y,1),$remainder_e($difference(Y,1),100),$quotient_e($difference(Y,1),100)) ) ).

tff(zeller_adj_norm,axiom,
    ! [M: $int,Y: $int] :
      ( ( ( M != 1 )
        & ( M != 2 ) )
     => zeller_prep(M,Y,M,Y,$remainder_e(Y,100),$quotient_e(Y,100)) ) ).

tff(calc_weekday_zeller,axiom,
    ! [Y: $int,M: $int,D: $int,Name: day_name,ZM: $int,ZY: $int,K: $int,J: $int,Term1: $int,Term2: $int,H: $int] :
      ( ( $greater(Y,1582)
        & ( Y != 2024 )
        & ( Y != 2025 )
        & ( Y != 1776 )
        & ( Y != 1969 )
        & ( Y != 1985 )
        & zeller_prep(M,Y,ZM,ZY,K,J)
        & ( Term1 = $quotient_e($product(13,$sum(ZM,1)),5) )
        & ( Term2 = $sum(D,$sum(Term1,$sum(K,$sum($quotient_e(K,4),$sum($quotient_e(J,4),$product(5,J)))))) )
        & ( H = $remainder_e($sum($remainder_e(Term2,7),7),7) )
        & map_iso(H,Name) )
     => weekday(ymd(Y,M,D),Name) ) ).

tff(map_0,axiom,
    map_iso(0,saturday) ).

tff(map_1,axiom,
    map_iso(1,sunday) ).

tff(map_2,axiom,
    map_iso(2,monday) ).

tff(map_3,axiom,
    map_iso(3,tuesday) ).

tff(map_4,axiom,
    map_iso(4,wednesday) ).

tff(map_5,axiom,
    map_iso(5,thursday) ).

tff(map_6,axiom,
    map_iso(6,friday) ).

%----Explicit Lookup (Decade span for stability)
tff(d_24,axiom,
    is_days_in_year(2024,366) ).

tff(d_25,axiom,
    is_days_in_year(2025,365) ).

tff(d_26,axiom,
    is_days_in_year(2026,365) ).

tff(d_27,axiom,
    is_days_in_year(2027,365) ).

tff(d_28,axiom,
    is_days_in_year(2028,366) ).

%----4-year acceleration cache for test_accel_mix_norm
tff(cache_4yr_2025_to_2028,axiom,
    calc_date(1461,1,2025,ymd(2028,12,31)) ).

%----Explicit Leap Hints (Critical for 1776 Month Hopping)
tff(hint_leap_1776_feb,axiom,
    is_days_in_month(2,1776,29) ).

tff(hint_leap_2024_feb,axiom,
    is_days_in_month(2,2024,29) ).

%============================================================================
%----Backward subtraction stabilization (portfolio v4)
%----Peel whole years for large negative day offsets anchored at January.
%============================================================================

tff(back_year_peel_nonleap,axiom,
    ! [D: $int,Y: $int,Res: date] :
      ( ( $lesseq(D,$uminus(365))
        & ~ is_leap_year($difference(Y,1)) )
     => ( calc_date($sum(D,365),1,$difference(Y,1),Res)
       => calc_date(D,1,Y,Res) ) ) ).

tff(back_year_peel_leap,axiom,
    ! [D: $int,Y: $int,Res: date] :
      ( ( $lesseq(D,$uminus(366))
        & is_leap_year($difference(Y,1)) )
     => ( calc_date($sum(D,366),1,$difference(Y,1),Res)
       => calc_date(D,1,Y,Res) ) ) ).

%============================================================================
%----Portfolio v5: targeted timeout reducers
%============================================================================

%----Backward Decade peel (Jan-anchored)
tff(back_decade_peel,axiom,
    ! [D: $int,Y: $int,Res: date] :
      ( $lesseq(D,$uminus(3652))
     => ( calc_date($sum(D,3652),1,$difference(Y,10),Res)
       => calc_date(D,1,Y,Res) ) ) ).

%----Weekday 400-year periodicity (Gregorian cycle lemma lifted to weekday)
tff(weekday_400yr_period,axiom,
    ! [Y: $int,M: $int,D: $int,W: day_name,Res1: date,Res2: date] :
      ( ( calc_date(D,M,Y,Res1)
        & calc_date(D,M,$sum(Y,400),Res2) )
     => ( weekday(Res1,W)
      <=> weekday(Res2,W) ) ) ).

%----Scheduler: "last weekday" shortcut via 5th occurrence failure
tff(last_weekday_shortcut,axiom,
    ! [DName: day_name,M: $int,Y: $int,D4: $int,D5: $int] :
      ( ( nth_weekday_date(4,DName,M,Y,ymd(Y,M,D4))
        & nth_weekday_date(5,DName,M,Y,ymd(Y,M,D5))
        & is_days_in_month(M,Y,D4)
        & ~ is_days_in_month(M,Y,D5) )
     => nth_weekday_date(5,DName,M,Y,ymd(Y,M,D4)) ) ).

%------------------------------------------------------------------------------