# -*- coding: utf-8 -*-

#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

import numpy as np

from gpmcc.utils.validation import validate_cctypes
from gpmcc.experiments.particle_dim import ParticleDim

import multiprocessing

def _particle_learn(args):
    dim, X, seed = args
    np.random.seed(seed)
    np.random.shuffle(X)
    dim.particle_learn(X)
    return dim

class ParticleEngine(object):
    """Particle Engine."""

    def __init__(self, dist, particles=1, distargs=None, multithread=True):
        validate_cctypes([dist])
        self.multithread = multithread
        self.map = map
        if self.multithread:
            self.pool = multiprocessing.Pool(multiprocessing.cpu_count())
            self.map = self.pool.map
        self.dist = dist
        self.distargs = distargs
        self.particles = particles
        self.dims = [ParticleDim(dist, distargs) for _ in xrange(particles)]

    def particle_learn(self, X, seeds=None):
        """Do particle learning in parallel."""
        if seeds is None:
            seeds = range(self.particles)
        assert len(seeds) == self.particles
        args = [(dim, X, seed) for (dim, seed) in zip(self.dims, seeds)]
        self.dims = self.map(_particle_learn, args)

    def get_dim(self, index):
        return self.dims[index]

@@ -764,19 +764,24 @@
 s):%0A    
-dim
+metadata
 , X, see
@@ -835,24 +835,70 @@
 .shuffle(X)%0A
+    dim = ParticleDim.from_metadata(metadata)%0A
     dim.part
@@ -909,16 +909,31 @@
 _learn(X
+, progress=True
 )%0A    re
@@ -940,16 +940,30 @@
 turn dim
+.to_metadata()
 %0A%0Aclass 
@@ -1721,16 +1721,30 @@
  = %5B(dim
+.to_metadata()
 , X, see
@@ -1761,16 +1761,28 @@
 m, seed)
+%0A           
  in zip(
@@ -1808,25 +1808,24 @@
         
-self.dims
+metadata
  = self.
@@ -1850,16 +1850,85 @@
 n, args)
+%0A        self.dims = %5BParticleDim.from_metadata(m) for m in metadata%5D
 %0A%0A    de

Implement multiproc for particles.