Repository: piskvorky/gensim

Issue:
Wrong calculation for max_iter_dump
In
https://github.com/RaRe-Technologies/gensim/blob/develop/gensim/models/wrappers/wordrank.py#L144
Shouldnt this line `max_iter_dump = iter / dump_period * dump_period - 1` just be 
`max_iter_dump = iter - dump_period` ?

To reproduce try these parameters:
`model = Wordrank.train(wr_path, data, out_dir, iter=100, dump_period=5)`
It will error out with -
```
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/ajkale/anaconda2/envs/wordrank/lib/python2.7/site-packages/gensim/models/wrappers/wordrank.py", line 146, in train
    copyfile('model_word_%d.txt' % max_iter_dump, 'wordrank.words')
  File "/home/ajkale/anaconda2/envs/wordrank/lib/python2.7/shutil.py", line 82, in copyfile
    with open(src, 'rb') as fsrc:
IOError: [Errno 2] No such file or directory: 'model_word_99.txt'
```

Mainly because `max_iter_dump = iter / dump_period * dump_period - 1`  calculates max_iter_dump=99 instead of 95.


Discussion:
Cc @parulsethi
Actually WordRank dumps the current iteration's file with the start of next iteration. So basically, we need to do 101 iterations for getting 100th iter file. And hence, the corresponding `max_iter_dump`. though I just noticed that `dump_period` division is redundant.

I've mentioned this thing under **Train Model** in [wordrank quickstart](https://github.com/RaRe-Technologies/gensim/blob/develop/docs/notebooks/WordRank_wrapper_quickstart.ipynb), but yeah anyone could easily miss on it.

I guess, better behavior would be to simply add 1 more iter in wrapper's train() itself (and so updating `max_iter_dump=iter`), rather than leaving it to user. So that, with the parameters you mentioned, you'll get embedding from `model_word_100.txt` only, better than `model_word_95.txt`. WDYT @ajkl?

Just saw your note in the quickstart notebook. Thats implicit knowledge and i think the code should handle it or warn and not crash.
About your `add 1 to iter` comment, wont that mean you end up making n+1 iterations than n (since iter is 0 indexed) ? Thats not ideal behavior either although you can argue its just 1 more iteration than what the user specified. I dont think its accurate though.
On second thoughts my earlier suggestion wont work either, it works only when `iter mod dump_period = 0` and same goes for your suggestion to `add 1 to iter` eg: `iter=102, dump_period=5` 

This is what I think it should be `max_iter_dump=(iter - 1) - (iter - 1) % dump_period` which basically is finding the largest number less than iter which is divisible by dump_period. 

Resolving patch:
diff --git a/gensim/models/wrappers/wordrank.py b/gensim/models/wrappers/wordrank.py
--- a/gensim/models/wrappers/wordrank.py
+++ b/gensim/models/wrappers/wordrank.py
@@ -46,7 +46,7 @@ class Wordrank(KeyedVectors):
     
     @classmethod
     def train(cls, wr_path, corpus_file, out_path, size=100, window=15, symmetric=1, min_count=5, max_vocab_size=0,
-              sgd_num=100, lrate=0.001, period=10, iter=91, epsilon=0.75, dump_period=10, reg=0, alpha=100,
+              sgd_num=100, lrate=0.001, period=10, iter=90, epsilon=0.75, dump_period=10, reg=0, alpha=100,
               beta=99, loss='hinge', memory=4.0, cleanup_files=True, sorted_vocab=1, ensemble=0):
         """
         `wr_path` is the path to the Wordrank directory.
@@ -113,6 +113,11 @@ def train(cls, wr_path, corpus_file, out_path, size=100, window=15, symmetric=1,
         with smart_open(meta_file, 'wb') as f:
             meta_info = "{0} {1}\n{2} {3}\n{4} {5}".format(numwords, numwords, numlines, cooccurrence_shuf_file, numwords, vocab_file)
             f.write(meta_info.encode('utf-8'))
+            
+        if iter % dump_period == 0:
+            iter += 1
+        else:
+            logger.warning('Resultant embedding would be from %d iteration', iter - iter % dump_period)
 
         wr_args = {
             'path': 'meta',
@@ -141,7 +146,7 @@ def train(cls, wr_path, corpus_file, out_path, size=100, window=15, symmetric=1,
         output = utils.check_output(args=cmd)
 
         # use embeddings from max. iteration's dump
-        max_iter_dump = iter / dump_period * dump_period - 1
+        max_iter_dump = iter - iter % dump_period
         copyfile('model_word_%d.txt' % max_iter_dump, 'wordrank.words')
         copyfile('model_context_%d.txt' % max_iter_dump, 'wordrank.contexts')
         model = cls.load_wordrank_model('wordrank.words', os.path.join('meta', vocab_file), 'wordrank.contexts', sorted_vocab, ensemble)


Test patch: