from __future__ import division

import tempfile
import unittest

from chainer import serializers
from chainer import testing
from chainer import training


class DummyUpdater(training.Updater):

    def __init__(self, iters_per_epoch):
        self.iteration = 0
        self.iters_per_epoch = iters_per_epoch

    def finalize(self):
        pass

    def get_all_optimizers(self):
        return {}

    def update(self):
        self.iteration += 1

    @property
    def epoch(self):
        return self.iteration // self.iters_per_epoch

    @property
    def epoch_detail(self):
        return self.iteration / self.iters_per_epoch

    @property
    def previous_epoch_detail(self):
        if self.iteration == 0:
            return None
        return (self.iteration - 1) / self.iters_per_epoch

    @property
    def is_new_epoch(self):
        return 0 <= self.iteration % self.iters_per_epoch < 1

    def serialize(self, serializer):
        self.iteration = serializer('iteration', self.iteration)


@testing.parameterize(*testing.product_dict([
    # iteration
    {
        'iters_per_epoch': 5, 'interval': (2, 'iteration'), 'resume': 4,
        'expected': [False, True, False, True, False, True, False]},
    # basic epoch
    {
        'iters_per_epoch': 1, 'interval': (3, 'epoch'), 'resume': 4,
        'expected': [False, False, True, False, False, True, False]},
    # fractional epoch
    {
        'iters_per_epoch': 2, 'interval': (1.5, 'epoch'), 'resume': 4,
        'expected': [False, False, True, False, False, True, False]},
    # unaligned epoch
    {
        'iters_per_epoch': 2.5, 'interval': (1, 'epoch'), 'resume': 3,
        'expected': [False, False, True, False, True, False, False]},
    # tiny epoch
    {
        'iters_per_epoch': 0.5, 'interval': (1, 'epoch'), 'resume': 4,
        'expected': [True, True, True, True, True, True, True]},
]))
class TestTrigger(unittest.TestCase):

    def test_trigger(self):
        trigger = training.trigger.IntervalTrigger(*self.interval)
        updater = DummyUpdater(self.iters_per_epoch)
        trainer = training.Trainer(updater)
        # before the first iteration, trigger should be False
        for expected in [False] + self.expected:
            self.assertEqual(trigger(trainer), expected)
            updater.update()

    def test_resumed_trigger(self):
        temp_file = tempfile.NamedTemporaryFile()

        trigger = training.trigger.IntervalTrigger(*self.interval)
        updater = DummyUpdater(self.iters_per_epoch)
        trainer = training.Trainer(updater)
        for expected in self.expected[:self.resume]:
            updater.update()
            self.assertEqual(trigger(trainer), expected)
        serializers.save_npz(temp_file.name, updater)

        trigger = training.trigger.IntervalTrigger(*self.interval)
        updater = DummyUpdater(self.iters_per_epoch)
        serializers.load_npz(temp_file.name, updater)
        trainer = training.Trainer(updater)
        for expected in self.expected[self.resume:]:
            updater.update()
            self.assertEqual(trigger(trainer), expected)


testing.run_module(__name__, __file__)

@@ -2361,19 +2361,12 @@
     
-temp_file =
+with
  tem
@@ -2390,19 +2390,40 @@
 aryFile(
-)%0A%0A
+delete=False) as f:%0A    
         
@@ -2481,32 +2481,36 @@
 terval)%0A        
+   
+ 
 updater = DummyU
@@ -2538,32 +2538,36 @@
 _epoch)%0A        
+    
 trainer = traini
@@ -2586,32 +2586,36 @@
 pdater)%0A        
+  
+  
 for expected in 
@@ -2643,16 +2643,20 @@
 esume%5D:%0A
+    
         
@@ -2680,32 +2680,36 @@
 e()%0A            
+    
 self.assertEqual
@@ -2737,32 +2737,36 @@
 pected)%0A        
+    
 serializers.save
@@ -2766,33 +2766,25 @@
 rs.save_npz(
-temp_file
+f
 .name, updat
@@ -2788,16 +2788,20 @@
 dater)%0A%0A
+    
         
@@ -2859,32 +2859,36 @@
 terval)%0A        
+    
 updater = DummyU
@@ -2916,32 +2916,36 @@
 _epoch)%0A        
+  
+  
 serializers.load
@@ -2953,17 +2953,9 @@
 npz(
-temp_file
+f
 .nam
@@ -2966,32 +2966,36 @@
 pdater)%0A        
+   
+ 
 trainer = traini
@@ -3006,32 +3006,36 @@
 rainer(updater)%0A
+    
         for expe
@@ -3075,32 +3075,36 @@
 :%5D:%0A            
+  
+  
 updater.update()
@@ -3096,32 +3096,36 @@
 pdater.update()%0A
+    
             self

use delete=False