public KAOSModel Generate()
        {
            if (_options.NbObstacles < _options.NbObstructions)
            {
                throw new ArgumentException("Cannot generate a model with more obstructions than obstacles.");
            }


            root = GenerateGoal();

            var goalToRefine     = new Stack <Tuple <Goal, int> > (new [] { new Tuple <Goal, int> (root, 0) });
            var obstacleToRefine = new Stack <Tuple <Obstacle, int> > ();
            var leafGoal         = new HashSet <string> ();
            var leafObstacles    = new HashSet <string> ();

            while (_model.Goals().Count() < _options.NbGoals)
            {
                var current = goalToRefine.Pop();
                leafGoal.Remove(current.Item1.Identifier);
                var r = GenerateGoalRefinement(current.Item1);
                foreach (var sg in r.SubGoals())
                {
                    goalToRefine.Push(new Tuple <Goal, int> (sg, current.Item2 + 1));
                    leafGoal.Add(sg.Identifier);
                }
            }

            var nbleafGoals    = _model.LeafGoals().Count();
            var maxObstruction = Math.Min(nbleafGoals, _options.NbObstructions);

            while (_model.ObstructedGoals().Count() < maxObstruction)
            {
                int randomIndex = _random.Next(0, nbleafGoals);
                var current     = _model.Goal(leafGoal.ElementAt(randomIndex));
                leafGoal.Remove(current.Identifier);
                nbleafGoals--;
                var r = GenerateObstruction(current);
                obstacleToRefine.Push(new Tuple <Obstacle, int> (r.Obstacle(), 0));
                leafObstacles.Add(r.ObstacleIdentifier);
            }

            while (_model.Obstacles().Count() < _options.NbObstacles)
            {
                var current = obstacleToRefine.Pop();
                leafObstacles.Remove(current.Item1.Identifier);
                var nbRefinement = _random.Next(_options.MinObstacleORBranchingFactor,
                                                _options.MaxObstacleORBranchingFactor);
                for (int i = 0; i < nbRefinement; i++)
                {
                    var r = GenerateObstacleRefinement(current.Item1);
                    foreach (var sg in r.SubObstacles())
                    {
                        obstacleToRefine.Push(new Tuple <Obstacle, int> (sg, current.Item2 + 1));
                        leafObstacles.Add(sg.Identifier);
                    }
                }
            }

            foreach (var current in leafObstacles)
            {
                _model.satisfactionRateRepository.AddObstacleSatisfactionRate(current,
                                                                              new DoubleSatisfactionRate(_random.NextDouble()));
            }

            return(_model);
        }