File size: 9,237 Bytes
f72237c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
import math


def calculate_compression_score(
    vmaf_score: float,
    compression_rate: float,
    vmaf_threshold: float,
    compression_weight: float = 0.70,
    quality_weight: float = 0.30,
    soft_threshold_margin: float = 5.0) -> tuple[float, float, float, str]:
    """
    Calculate compression score that rewards hitting VMAF threshold with good compression.
    
    Scoring Philosophy:
    - Compression is primary goal (70% weight by default)
    - VMAF at/above threshold is rewarded with diminishing returns (30% weight)
    - 15x compression ratio = 1.0 compression component
    - Exceeding VMAF threshold gives modest bonus (not penalty)
    
    Three scoring zones:
    1. Below hard cutoff (threshold - 5): Score = 0
    2. Soft zone (threshold - 5 to threshold): Gradual recovery
    3. Above threshold: Full scoring with quality bonus
    
    Args:
        vmaf_score: VMAF quality score (0-100)
        compression_rate: Size ratio compressed/original (0-1, lower is better)
        vmaf_threshold: Required VMAF threshold (e.g., 85, 90, 95)
        compression_weight: Weight for compression component (default: 0.70)
        quality_weight: Weight for quality component (default: 0.30)
        soft_threshold_margin: Points below threshold before hard cutoff (default: 5.0)
    
    Returns:
        Tuple of (final_score, compression_component, quality_component, reason)
        where final_score is in range [0.0, 1.0]
    """
    
    # Validate that weights sum to 1.0
    if abs(compression_weight + quality_weight - 1.0) > 0.01:
        raise ValueError(f"Weights must sum to 1.0, got {compression_weight + quality_weight}")
    
    # Calculate hard cutoff point
    hard_cutoff = vmaf_threshold - soft_threshold_margin
    
    # ========================================================================
    # CASE 0: No Meaningful Compression - Immediate Failure
    # ========================================================================
    # If compression_rate >= 0.80 (less than 1.25x compression), this is likely
    # the miner returning the same video or minimal compression to exploit high VMAF.
    # Zero the entire score to prevent this exploit.
    if compression_rate >= 0.80:
        compression_ratio = 1 / compression_rate if compression_rate > 0 else 1.0
        return 0.0, 0.0, 0.0, f"No meaningful compression (ratio: {compression_ratio:.2f}x, rate: {compression_rate:.2f}). Minimum 1.25x required."
    
    # ========================================================================
    # CASE 1: Below Hard Cutoff - Immediate Failure
    # ========================================================================
    # If VMAF is more than 5 points below threshold, quality is unacceptable
    if vmaf_score < hard_cutoff:
        return 0.0, 0.0, 0.0, f"VMAF {vmaf_score:.2f} below hard cutoff ({hard_cutoff:.2f})"
    
    # ========================================================================
    # CASE 2: Soft Threshold Zone (threshold-5 to threshold)
    # ========================================================================
    # Gradual recovery zone where both quality and compression matter
    if vmaf_score < vmaf_threshold:
        # Calculate position in soft zone (0.0 to 1.0)
        # Example: VMAF 93 with threshold 95 and margin 5
        # soft_zone_position = (93 - 90) / 5 = 0.6
        soft_zone_position = (vmaf_score - hard_cutoff) / soft_threshold_margin
        
        """
        Quality factor uses scaled function to reach 0.7 at threshold:
        f(x) = 0.7 * xΒ²
        
        - At hard cutoff (x=0): factor = 0.0
        - At midpoint (x=0.5): factor = 0.175
        - At threshold (x=1): factor = 0.7
        
        This ensures continuity with the above-threshold quality component
        which starts at 0.7 when VMAF equals threshold.
        """
        quality_factor = 0.7 * (soft_zone_position ** 2)
        
        # Calculate compression component (compression_rate < 0.80 guaranteed by CASE 0)
        compression_ratio = 1 / compression_rate
        
        if compression_ratio <= 20:
            """
            Compression scoring for 1x to 20x:
            f(r) = ((r - 1) / 19) ^ 1.5
            
            Where r is compression ratio (e.g., 5 for 5x compression)
            - At 1x: component = 0
            - At 2x: component β‰ˆ 0.23
            - At 5x: component β‰ˆ 0.65
            - At 10x: component β‰ˆ 0.89
            - At 15x: component β‰ˆ 0.97
            - At 20x: component = 1.0
            
            The exponent 1.5 provides:
            - Slow growth initially (encouraging minimum viable compression)
            - Steeper growth in practical range (5-15x)
            - Reaches 1.0 exactly at 20x
            """
            compression_component = ((compression_ratio - 1) / 19) ** 1.5
        else:
            """
            Bonus for exceptional compression (>20x):
            f(r) = 1.0 + 0.3 * ln(r / 20)
            
            Logarithmic bonus rewards exceptional performance:
            - At 20x: component = 1.0 (continuous at boundary)
            - At 30x: component β‰ˆ 1.12
            - At 40x: component β‰ˆ 1.21
            - At 60x: component β‰ˆ 1.30 (capped)
            
            Natural log ensures smooth transition from linear region.
            """
            compression_component = 1.0 + 0.3 * math.log(compression_ratio / 20)
        
        compression_component = min(1.3, compression_component)
        
        # In soft zone, both compression AND quality factor matter
        # If you're below threshold, you need good compression to recover
        final_score = compression_component * quality_factor
        
        return min(1.0, final_score), compression_component, quality_factor, f"VMAF {vmaf_score:.2f} in soft zone (quality factor: {quality_factor:.2f})"
    
    # ========================================================================
    # CASE 3: Above Threshold - Full Scoring with Quality Bonus
    # ========================================================================
    else:
        # Calculate how much VMAF exceeds threshold
        vmaf_excess = vmaf_score - vmaf_threshold
        max_vmaf_excess = 100 - vmaf_threshold  # Maximum possible excess to VMAF 100
        
        """
        Quality component rewards exceeding threshold with linear interpolation:
        f(x) = 0.7 + 0.3 * (x / max_excess)
        
        Where x is VMAF points above threshold:
        - At threshold (x=0): component = 0.7
        - At threshold + 25% of range: component = 0.775
        - At threshold + 50% of range: component = 0.85
        - At threshold + 75% of range: component = 0.925
        - At VMAF 100: component = 1.0
        
        Example with threshold=85:
        - At 85: 0.7 + 0.3 * (0/15) = 0.7
        - At 90: 0.7 + 0.3 * (5/15) = 0.8
        - At 95: 0.7 + 0.3 * (10/15) = 0.9
        - At 100: 0.7 + 0.3 * (15/15) = 1.0
        
        This provides steady linear growth from 0.7 to 1.0 as VMAF approaches perfect quality.
        """
        quality_component = 0.7 + 0.3 * min(1.0, vmaf_excess / max_vmaf_excess)
        
        # Calculate compression component (compression_rate < 0.80 guaranteed by CASE 0)
        compression_ratio = 1 / compression_rate
        
        if compression_ratio <= 20:
            """
            Good compression scoring (1.25x to 20x):
            f(r) = ((r - 1.25) / 18.75) ^ 1.2
            
            Starting from 1.25x to give smooth transition from poor zone:
            - At 1.25x: component = 0.025
            - At 2x: component β‰ˆ 0.24
            - At 5x: component β‰ˆ 0.64
            - At 10x: component β‰ˆ 0.88
            - At 15x: component β‰ˆ 0.96
            - At 20x: component = 1.0
            
            The exponent 1.2 provides balanced reward curve.
            """
            compression_component = ((compression_ratio - 1.25) / 18.75) ** 1.2 + 0.025
        else:
            """
            Exceptional compression bonus (>20x):
            f(r) = 1.0 + 0.3 * ln(r / 20)
            
            Logarithmic bonus up to 1.3 cap:
            - At 20x: component = 1.0 (continuous at boundary)
            - At 30x: component β‰ˆ 1.12
            - At 40x: component β‰ˆ 1.21
            - At 60x: component β‰ˆ 1.30 (capped)
            
            Natural log ensures smooth transition from power region.
            """
            compression_component = 1.0 + 0.3 * math.log(compression_ratio / 20)
        
        compression_component = min(1.3, compression_component)
        reason_suffix = "" if compression_ratio < 10 else " (excellent compression)"
        
        """
        Final score is weighted combination:
        final_score = w_c * compression_component + w_q * quality_component
        
        Default: 70% compression + 30% quality
        Capped at 1.0 to maintain normalized scoring
        """
        final_score = (compression_weight * compression_component + 
                      quality_weight * quality_component)
        
        final_score = min(1.0, final_score)

        return final_score, compression_component, quality_component, f"success{reason_suffix}"