diff --git a/.gitignore b/.gitignore index 75ac08e..e3f930e 100644 --- a/.gitignore +++ b/.gitignore @@ -100,4 +100,6 @@ ENV/ # mypy .mypy_cache/ -.idea/ \ No newline at end of file +.idea/ + +sphinx/ \ No newline at end of file diff --git a/README.md b/README.md index 40b7ab4..256e6b6 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ -
+
+
[![Build Status](https://travis-ci.org/100/Solid.svg?branch=master)](https://travis-ci.org/100/Solid) [![MIT License](https://img.shields.io/dub/l/vibe-d.svg)](https://github.com/100/Cranium/blob/master/LICENSE) -## *Solid* is a simple Python library for gradient-free optimization. +## *Solid* is a Python library for gradient-free optimization. #### It contains basic versions of many of the most common algorithms, and allows for very rapid development using them. @@ -15,13 +16,13 @@
## Current Features: -* Genetic Algorithm -* Evolutionary Algorithm -* Simulated Annealing -* Particle Swarm Optimization -* Tabu Search -* Harmony Search -* Stochastic Hill Climb +* [Genetic Algorithm](https://github.com/100/Solid/blob/master/Solid/GeneticAlgorithm.py) +* [Evolutionary Algorithm](https://github.com/100/Solid/blob/master/Solid/EvolutionaryAlgorithm.py) +* [Simulated Annealing](https://github.com/100/Solid/blob/master/Solid/SimulatedAnnealing.py) +* [Particle Swarm Optimization](https://github.com/100/Solid/blob/master/Solid/ParticleSwarm.py) +* [Tabu Search](https://github.com/100/Solid/blob/master/Solid/TabuSearch.py) +* [Harmony Search](https://github.com/100/Solid/blob/master/Solid/HarmonySearch.py) +* [Stochastic Hill Climb](https://github.com/100/Solid/blob/master/Solid/StochasticHillClimb.py)
@@ -65,13 +66,13 @@ class Algorithm(EvolutionaryAlgorithm): def test_algorithm(): algorithm = Algorithm(.5, .7, 500, max_fitness=None) - algorithm.run() + best_solution, best_objective_value = algorithm.run() ```
-## Building and Testing +## Testing To run tests, look in the ```tests``` folder. diff --git a/docs/.buildinfo b/docs/.buildinfo new file mode 100644 index 0000000..2032a2d --- /dev/null +++ b/docs/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: b691e48017afb30514be38e8c3446b04 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/docs/Solid.html b/docs/Solid.html new file mode 100644 index 0000000..4d47be5 --- /dev/null +++ b/docs/Solid.html @@ -0,0 +1,749 @@ + + + + + + + + Solid package — Solid 0.11 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+

Solid package

+
+

Submodules

+
+
+

Solid.EvolutionaryAlgorithm module

+
+
+class Solid.EvolutionaryAlgorithm.EvolutionaryAlgorithm(crossover_rate, mutation_rate, max_steps, max_fitness=None)[source]
+

Bases: object

+

Conducts evolutionary algorithm

+
+
+best_fitness = None
+
+ +
+
+best_member = None
+
+ +
+
+crossover_rate = None
+
+ +
+
+cur_steps = None
+
+ +
+
+fitnesses = None
+
+ +
+
+max_fitness = None
+
+ +
+
+max_steps = None
+
+ +
+
+mutation_rate = None
+
+ +
+
+population = None
+
+ +
+
+run(verbose=True)[source]
+

Conducts evolutionary algorithm

+ +++ + + + + + +
Parameters:verbose – indicates whether or not to print progress regularly
Returns:best state and best objective function value
+
+ +
+ +
+
+Solid.EvolutionaryAlgorithm.random() → x in the interval [0, 1).
+
+ +
+
+

Solid.GeneticAlgorithm module

+
+
+class Solid.GeneticAlgorithm.GeneticAlgorithm(crossover_rate, mutation_rate, max_steps, max_fitness=None)[source]
+

Bases: object

+

Conducts genetic algorithm

+
+
+best_fitness = None
+
+ +
+
+best_member = None
+
+ +
+
+crossover_rate = None
+
+ +
+
+cur_steps = None
+
+ +
+
+fitnesses = None
+
+ +
+
+max_fitness = None
+
+ +
+
+max_steps = None
+
+ +
+
+mutation_rate = None
+
+ +
+
+population = None
+
+ +
+
+run(verbose=True)[source]
+

Conducts genetic algorithm

+ +++ + + + + + +
Parameters:verbose – indicates whether or not to print progress regularly
Returns:best state and best objective function value
+
+ +
+ +
+
+Solid.GeneticAlgorithm.random() → x in the interval [0, 1).
+
+ +
+
+

Solid.HarmonySearch module

+
+
+class Solid.HarmonySearch.HarmonySearch(hms, hmcr, par, fw, max_steps, max_score=None)[source]
+

Bases: object

+

Conducts harmony search

+
+
+best = None
+
+ +
+
+cur_steps = None
+
+ +
+
+fw = None
+
+ +
+
+hmcr = None
+
+ +
+
+hms = None
+
+ +
+
+max_score = None
+
+ +
+
+max_steps = None
+
+ +
+
+memory = None
+
+ +
+
+par = None
+
+ +
+
+run(verbose=True)[source]
+

Conducts harmony search

+ +++ + + + + + +
Parameters:verbose – indicates whether or not to print progress regularly
Returns:best state and objective function value of best state
+
+ +
+
+scores = None
+
+ +
+ +
+
+Solid.HarmonySearch.random() → x in the interval [0, 1).
+
+ +
+
+

Solid.ParticleSwarm module

+
+
+class Solid.ParticleSwarm.ParticleSwarm(swarm_size, member_size, lower_bound, upper_bound, c1, c2, c3, max_steps, min_objective=None)[source]
+

Bases: object

+

Conducts particle swarm optimization

+
+
+best = None
+
+ +
+
+c1 = None
+
+ +
+
+c2 = None
+
+ +
+
+c3 = None
+
+ +
+
+cur_steps = None
+
+ +
+
+global_best = None
+
+ +
+
+lower_bound = None
+
+ +
+
+max_steps = None
+
+ +
+
+member_size = None
+
+ +
+
+min_objective = None
+
+ +
+
+pos = None
+
+ +
+
+run(verbose=True)[source]
+

Conducts particle swarm optimization

+ +++ + + + + + +
Parameters:verbose – indicates whether or not to print progress regularly
Returns:best member of swarm and objective function value of best member of swarm
+
+ +
+
+scores = None
+
+ +
+
+swarm_size = None
+
+ +
+
+upper_bound = None
+
+ +
+
+vel = None
+
+ +
+ +
+
+Solid.ParticleSwarm.random() → x in the interval [0, 1).
+
+ +
+
+Solid.ParticleSwarm.uniform(low=0.0, high=1.0, size=None)
+

Draw samples from a uniform distribution.

+

Samples are uniformly distributed over the half-open interval +[low, high) (includes low, but excludes high). In other words, +any value within the given interval is equally likely to be drawn +by uniform.

+
+
low : float or array_like of floats, optional
+
Lower boundary of the output interval. All values generated will be +greater than or equal to low. The default value is 0.
+
high : float or array_like of floats
+
Upper boundary of the output interval. All values generated will be +less than high. The default value is 1.0.
+
size : int or tuple of ints, optional
+
Output shape. If the given shape is, e.g., (m, n, k), then +m * n * k samples are drawn. If size is None (default), +a single value is returned if low and high are both scalars. +Otherwise, np.broadcast(low, high).size samples are drawn.
+
+
+
out : ndarray or scalar
+
Drawn samples from the parameterized uniform distribution.
+
+

randint : Discrete uniform distribution, yielding integers. +random_integers : Discrete uniform distribution over the closed

+
+
interval [low, high].
+

random_sample : Floats uniformly distributed over [0, 1). +random : Alias for random_sample. +rand : Convenience function that accepts dimensions as input, e.g.,

+
+
rand(2,2) would generate a 2-by-2 array of floats, +uniformly distributed over [0, 1).
+

The probability density function of the uniform distribution is

+

anywhere within the interval [a, b), and zero elsewhere.

+

When high == low, values of low will be returned. +If high < low, the results are officially undefined +and may eventually raise an error, i.e. do not rely on this +function to behave when passed arguments satisfying that +inequality condition.

+

Draw samples from the distribution:

+
>>> s = np.random.uniform(-1,0,1000)
+
+
+

All values are within the given interval:

+
>>> np.all(s >= -1)
+True
+>>> np.all(s < 0)
+True
+
+
+

Display the histogram of the samples, along with the +probability density function:

+
>>> import matplotlib.pyplot as plt
+>>> count, bins, ignored = plt.hist(s, 15, normed=True)
+>>> plt.plot(bins, np.ones_like(bins), linewidth=2, color='r')
+>>> plt.show()
+
+
+
+ +
+
+

Solid.SimulatedAnnealing module

+
+
+class Solid.SimulatedAnnealing.SimulatedAnnealing(initial_state, temp_begin, schedule_constant, max_steps, min_energy=None, schedule=’exponential’)[source]
+

Bases: object

+

Conducts simulated annealing algorithm

+
+
+adjust_temp = None
+
+ +
+
+best_energy = None
+
+ +
+
+best_state = None
+
+ +
+
+cur_steps = 0
+
+ +
+
+current_energy = None
+
+ +
+
+current_state = None
+
+ +
+
+current_temp = None
+
+ +
+
+initial_state = None
+
+ +
+
+max_steps = None
+
+ +
+
+min_energy = None
+
+ +
+
+run(verbose=True)[source]
+

Conducts simulated annealing

+ +++ + + + + + +
Parameters:verbose – indicates whether or not to print progress regularly
Returns:best state and best energy
+
+ +
+
+start_temp = None
+
+ +
+ +
+
+Solid.SimulatedAnnealing.random() → x in the interval [0, 1).
+
+ +
+
+

Solid.StochasticHillClimb module

+
+
+class Solid.StochasticHillClimb.StochasticHillClimb(initial_state, temp, max_steps, max_objective=None)[source]
+

Bases: object

+

Conducts stochastic hill climb

+
+
+best_objective = None
+
+ +
+
+best_state = None
+
+ +
+
+cur_steps = 0
+
+ +
+
+current_state = None
+
+ +
+
+initial_state = None
+
+ +
+
+max_objective = None
+
+ +
+
+max_steps = None
+
+ +
+
+run(verbose=True)[source]
+

Conducts hill climb

+ +++ + + + + + +
Parameters:verbose – indicates whether or not to print progress regularly
Returns:best state and best objective function value
+
+ +
+
+temp = None
+
+ +
+ +
+
+Solid.StochasticHillClimb.random() → x in the interval [0, 1).
+
+ +
+
+

Solid.TabuSearch module

+
+
+class Solid.TabuSearch.TabuSearch(initial_state, tabu_size, max_steps, max_score=None)[source]
+

Bases: object

+

Conducts tabu search

+
+
+best = None
+
+ +
+
+cur_steps = None
+
+ +
+
+current = None
+
+ +
+
+initial_state = None
+
+ +
+
+max_score = None
+
+ +
+
+max_steps = None
+
+ +
+
+run(verbose=True)[source]
+

Conducts tabu search

+ +++ + + + + + +
Parameters:verbose – indicates whether or not to print progress regularly
Returns:best state and objective function value of best state
+
+ +
+
+tabu_list = None
+
+ +
+
+tabu_size = None
+
+ +
+ +
+
+Solid.TabuSearch.random() → x in the interval [0, 1).
+
+ +
+
+

Module contents

+
+
+ + +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_modules/Solid/EvolutionaryAlgorithm.html b/docs/_modules/Solid/EvolutionaryAlgorithm.html new file mode 100644 index 0000000..14119f8 --- /dev/null +++ b/docs/_modules/Solid/EvolutionaryAlgorithm.html @@ -0,0 +1,295 @@ + + + + + + + + Solid.EvolutionaryAlgorithm — Solid 0.11 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for Solid.EvolutionaryAlgorithm

+from abc import ABCMeta, abstractmethod
+from copy import deepcopy
+from random import random, shuffle
+
+
+
[docs]class EvolutionaryAlgorithm: + """ + Conducts evolutionary algorithm + """ + __metaclass__ = ABCMeta + + population = None + fitnesses = None + + crossover_rate = None + + mutation_rate = None + + cur_steps = None + best_fitness = None + best_member = None + + max_steps = None + max_fitness = None + + def __init__(self, crossover_rate, mutation_rate, max_steps, max_fitness=None): + """ + + :param crossover_rate: probability of crossover + :param mutation_rate: probability of mutation + :param max_steps: maximum steps to run genetic algorithm for + :param max_fitness: fitness value to stop algorithm once reached + """ + if isinstance(crossover_rate, float): + if crossover_rate >= 0 and crossover_rate <= 1: + self.crossover_rate = crossover_rate + else: + raise ValueError('Crossover rate must be a float between 0 and 1') + else: + raise ValueError('Crossover rate must be a float between 0 and 1') + + if isinstance(mutation_rate, float): + if mutation_rate >= 0 and mutation_rate <= 1: + self.mutation_rate = mutation_rate + else: + raise ValueError('Mutation rate must be a float between 0 and 1') + else: + raise ValueError('Mutation rate must be a float between 0 and 1') + + if isinstance(max_steps, int) and max_steps > 0: + self.max_steps = max_steps + else: + raise ValueError('Maximum steps must be a positive integer') + + if max_fitness is not None: + if isinstance(max_fitness, (int, float)): + self.max_fitness = float(max_fitness) + else: + raise ValueError('Maximum fitness must be a numeric type') + + def __str__(self): + return ('EVOLUTIONARY ALGORITHM: \n' + + 'CURRENT STEPS: %d \n' + + 'BEST FITNESS: %f \n' + + 'BEST MEMBER: %s \n\n') % \ + (self.cur_steps, self.best_fitness, str(self.best_member)) + + def __repr__(self): + return self.__str__() + + def _clear(self): + """ + Resets the variables that are altered on a per-run basis of the algorithm + + :return: None + """ + self.cur_steps = 0 + self.population = None + self.fitnesses = None + self.best_member = None + self.best_fitness = None + + @abstractmethod + def _initial_population(self): + """ + Generates initial population + + :return: list of members of population + """ + pass + + @abstractmethod + def _fitness(self, member): + """ + Evaluates fitness of a given member + + :param member: a member + :return: fitness of member + """ + pass + + def _populate_fitness(self): + """ + Calculates fitness of all members of current population + + :return: None + """ + self.fitnesses = list([self._fitness(x) for x in self.population]) + + def _most_fit(self): + """ + Finds most fit member of current population + + :return: most fit member and most fit member's fitness + """ + best_idx = 0 + cur_idx = 0 + for x in self.fitnesses: + if x > self.fitnesses[best_idx]: + best_idx = cur_idx + cur_idx += 1 + return self.population[best_idx], self.fitnesses[best_idx] + + def _select_n(self, n): + """ + Probabilistically selects n members from current population using + roulette-wheel selection + + :param n: number of members to select + :return: n members + """ + shuffle(self.population) + total_fitness = sum(self.fitnesses) + if total_fitness != 0: + probs = list([self._fitness(x) / total_fitness for x in self.population]) + else: + return self.population[0:n] + res = [] + for _ in range(n): + r = random() + sum_ = 0 + for i, x in enumerate(probs): + sum_ += probs[i] + if r <= sum_: + res.append(deepcopy(self.population[i])) + break + return res + + @abstractmethod + def _crossover(self, parent1, parent2): + """ + Creates new member of population by combining two parent members + + :param parent1: a member + :param parent2: a member + :return: member made by combining elements of both parents + """ + pass + + @abstractmethod + def _mutate(self, member): + """ + Randomly mutates a member + + :param member: a member + :return: mutated member + """ + pass + +
[docs] def run(self, verbose=True): + """ + Conducts evolutionary algorithm + + :param verbose: indicates whether or not to print progress regularly + :return: best state and best objective function value + """ + self._clear() + self.population = self._initial_population() + self._populate_fitness() + self.best_member, self.best_fitness = self._most_fit() + num_copy = max(int((1 - self.crossover_rate) * len(self.population)), 2) + num_crossover = len(self.population) - num_copy + for i in range(self.max_steps): + self.cur_steps += 1 + + if ((i + 1) % 100 == 0) and verbose: + print self + + self.population = self._select_n(num_copy) + self._populate_fitness() + + parents = self._select_n(2) + for _ in range(num_crossover): + self.population.append(self._crossover(*parents)) + + self.population = list([self._mutate(x) for x in self.population]) + self._populate_fitness() + + best_member, best_fitness = self._most_fit() + if best_fitness > self.best_fitness: + self.best_fitness = best_fitness + self.best_member = deepcopy(best_member) + + if self.max_fitness is not None and self.best_fitness >= self.max_fitness: + print "TERMINATING - REACHED MAXIMUM FITNESS" + return self.best_member, self.best_fitness + print "TERMINATING - REACHED MAXIMUM STEPS" + return self.best_member, self.best_fitness
+
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_modules/Solid/GeneticAlgorithm.html b/docs/_modules/Solid/GeneticAlgorithm.html new file mode 100644 index 0000000..75d6720 --- /dev/null +++ b/docs/_modules/Solid/GeneticAlgorithm.html @@ -0,0 +1,298 @@ + + + + + + + + Solid.GeneticAlgorithm — Solid 0.11 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for Solid.GeneticAlgorithm

+from abc import ABCMeta, abstractmethod
+from copy import deepcopy
+from random import randint, random, shuffle
+
+
+
[docs]class GeneticAlgorithm: + """ + Conducts genetic algorithm + """ + __metaclass__ = ABCMeta + + population = None + fitnesses = None + + crossover_rate = None + + mutation_rate = None + + cur_steps = None + best_fitness = None + best_member = None + + max_steps = None + max_fitness = None + + def __init__(self, crossover_rate, mutation_rate, max_steps, max_fitness=None): + """ + + :param crossover_rate: probability of crossover + :param mutation_rate: probability of mutation + :param max_steps: maximum steps to run genetic algorithm for + :param max_fitness: fitness value to stop algorithm once reached + """ + if isinstance(crossover_rate, float): + if crossover_rate >= 0 and crossover_rate <= 1: + self.crossover_rate = crossover_rate + else: + raise ValueError('Crossover rate must be a float between 0 and 1') + else: + raise ValueError('Crossover rate must be a float between 0 and 1') + + if isinstance(mutation_rate, float): + if mutation_rate >= 0 and mutation_rate <= 1: + self.mutation_rate = mutation_rate + else: + raise ValueError('Mutation rate must be a float between 0 and 1') + else: + raise ValueError('Mutation rate must be a float between 0 and 1') + + if isinstance(max_steps, int) and max_steps > 0: + self.max_steps = max_steps + else: + raise ValueError('Maximum steps must be a positive integer') + + if max_fitness is not None: + if isinstance(max_fitness, (int, float)): + self.max_fitness = float(max_fitness) + else: + raise ValueError('Maximum fitness must be a numeric type') + + def __str__(self): + return ('GENETIC ALGORITHM: \n' + + 'CURRENT STEPS: %d \n' + + 'BEST FITNESS: %f \n' + + 'BEST MEMBER: %s \n\n') % \ + (self.cur_steps, self.best_fitness, str(self.best_member)) + + def __repr__(self): + return self.__str__() + + def _clear(self): + """ + Resets the variables that are altered on a per-run basis of the algorithm + + :return: None + """ + self.cur_steps = 0 + self.population = None + self.fitnesses = None + self.best_member = None + self.best_fitness = None + + @abstractmethod + def _initial_population(self): + """ + Generates initial population - + members must be represented by a list of binary-values integers + + :return: list of members of population + """ + pass + + @abstractmethod + def _fitness(self, member): + """ + Evaluates fitness of a given member + + :param member: a member + :return: fitness of member + """ + pass + + def _populate_fitness(self): + """ + Calculates fitness of all members of current population + + :return: None + """ + self.fitnesses = list([self._fitness(x) for x in self.population]) + + def _most_fit(self): + """ + Finds most fit member of current population + + :return: most fit member and most fit member's fitness + """ + best_idx = 0 + cur_idx = 0 + for x in self.fitnesses: + if x > self.fitnesses[best_idx]: + best_idx = cur_idx + cur_idx += 1 + return self.population[best_idx], self.fitnesses[best_idx] + + def _select_n(self, n): + """ + Probabilistically selects n members from current population using + roulette-wheel selection + + :param n: number of members to select + :return: n members + """ + shuffle(self.population) + total_fitness = sum(self.fitnesses) + if total_fitness != 0: + probs = list([self._fitness(x) / total_fitness for x in self.population]) + else: + return self.population[0:n] + res = [] + for _ in range(n): + r = random() + sum_ = 0 + for i, x in enumerate(probs): + sum_ += probs[i] + if r <= sum_: + res.append(deepcopy(self.population[i])) + break + return res + + def _crossover(self, parent1, parent2): + """ + Creates new member of population by combining two parent members + + :param parent1: a member + :param parent2: a member + :return: member made by combining elements of both parents + """ + partition = randint(0, len(self.population[0]) - 1) + return parent1[0:partition] + parent2[partition:] + + def _mutate(self, member): + """ + Randomly mutates a member + + :param member: a member + :return: mutated member + """ + if self.mutation_rate >= random(): + idx = randint(0, len(member) - 1) + member[idx] = 1 if member[idx] == 0 else 1 + return member + +
[docs] def run(self, verbose=True): + """ + Conducts genetic algorithm + + :param verbose: indicates whether or not to print progress regularly + :return: best state and best objective function value + """ + self._clear() + self.population = self._initial_population() + self._populate_fitness() + self.best_member, self.best_fitness = self._most_fit() + num_copy = max(int((1 - self.crossover_rate) * len(self.population)), 2) + num_crossover = len(self.population) - num_copy + for i in range(self.max_steps): + self.cur_steps += 1 + + if ((i + 1) % 100 == 0) and verbose: + print self + + self.population = self._select_n(num_copy) + self._populate_fitness() + + parents = self._select_n(2) + for _ in range(num_crossover): + self.population.append(self._crossover(*parents)) + + self.population = list([self._mutate(x) for x in self.population]) + self._populate_fitness() + + best_member, best_fitness = self._most_fit() + if best_fitness > self.best_fitness: + self.best_fitness = best_fitness + self.best_member = deepcopy(best_member) + + if self.max_fitness is not None and self.best_fitness >= self.max_fitness: + print "TERMINATING - REACHED MAXIMUM FITNESS" + return self.best_member, self.best_fitness + print "TERMINATING - REACHED MAXIMUM STEPS" + return self.best_member, self.best_fitness
+
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_modules/Solid/HarmonySearch.html b/docs/_modules/Solid/HarmonySearch.html new file mode 100644 index 0000000..1e57ad0 --- /dev/null +++ b/docs/_modules/Solid/HarmonySearch.html @@ -0,0 +1,254 @@ + + + + + + + + Solid.HarmonySearch — Solid 0.11 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for Solid.HarmonySearch

+from abc import ABCMeta, abstractmethod
+from random import choice, random, uniform
+from numpy import argmax, argmin
+
+
+
[docs]class HarmonySearch: + """ + Conducts harmony search + """ + __metaclass__ = ABCMeta + + cur_steps = None + + hms = None + hmcr = None + par = None + fw = None + + memory = None + scores = None + best = None + + max_steps = None + max_score = None + + def __init__(self, hms, hmcr, par, fw, max_steps, max_score=None): + """ + + :param hms: harmony memory size + :param hmcr: harmony memory considering rate + :param par: pitch adjustment rate + :param fw: fret width + :param max_steps: maximum number of steps to run algorithm for + :param max_score: objective function value to stop algorithm once reached + """ + if isinstance(hms, int) and hms > 0: + self.hms = hms + else: + raise TypeError('Harmony memory size must be a positive integer') + + if isinstance(hmcr, float) and 0 <= hmcr <= 1: + self.hmcr = hmcr + else: + raise TypeError('Harmony memory considering rate must be a float between 0 and 1') + + if isinstance(par, float) and 0 <= par <= 1: + self.par = par + else: + raise TypeError('Pitch adjustment rate must be a float between 0 and 1') + + if isinstance(fw, (int, float)): + self.fw = float(fw) + else: + raise TypeError('Fret width must be a numeric type') + + if isinstance(max_steps, int) and max_steps > 0: + self.max_steps = max_steps + else: + raise TypeError('Max steps must be a positive integer') + + if max_score is not None: + if isinstance(max_score, (int, float)): + self.max_score = max_score + else: + raise TypeError('Max score must be a numeric type') + + def __str__(self): + return ('HARMONY SEARCH: \n' + + 'CURRENT STEPS: %d \n' + + 'BEST SCORE: %f \n' + + 'BEST MEMBER: %s \n\n') % \ + (self.cur_steps, self._score(self.best), str(self.best)) + + def __repr__(self): + return self.__str__() + + def _clear(self): + """ + Resets the variables that are altered on a per-run basis of the algorithm + + :return: None + """ + self.cur_steps = 0 + self.memory = list([self._random_harmony() for _ in range(self.hms)]) + self.scores = None + + @abstractmethod + def _random_harmony(self): + """ + Generates a random harmony, represented as a list of floats + + :return: list of harmonies + """ + pass + + @abstractmethod + def _score(self, harmony): + """ + Returns score of a harmony + + :param harmony: a harmony + :return: score of harmony + """ + pass + + def _score_all(self): + """ + Finds score of all current harmonies in memory + + :return: None + """ + self.scores = list([self._score(x) for x in self.memory]) + + def _worst_score(self): + """ + Returns index of worst harmony in memory + + :return: index of worst harmony in memory + """ + return argmin(self.scores) + + def _best_score(self): + """ + Returns index of best harmony in memory + + :return: index of best harmony in memory + """ + return argmax(self.scores) + +
[docs] def run(self, verbose=True): + """ + Conducts harmony search + + :param verbose: indicates whether or not to print progress regularly + :return: best state and objective function value of best state + """ + self._clear() + self._score_all() + for i in range(self.max_steps): + self.cur_steps += 1 + + if ((i + 1) % 100 == 0) and verbose: + print self + + self._score_all() + + selected = [0.] * len(self.memory[0]) + for i in range(len(selected)): + if self.hmcr >= random(): + selected_component = choice(self.memory)[i] + if self.par >= random(): + selected_component += uniform(-1, 1) * self.fw + else: + selected_component = self._random_harmony()[i] + selected[i] = selected_component + + if self._score(selected) > self._score(self.memory[self._worst_score()]): + self.memory[self._worst_score()] = selected + self.scores[self._worst_score()] = self._score(selected) + + self.best = self.memory[self._best_score()] + + if self.max_score is not None and self._score(self.best) > self.max_score: + print "TERMINATING - REACHED MAXIMUM SCORE" + return self.best, self._score(self.best) + print "TERMINATING - REACHED MAXIMUM STEPS" + return self.best, self._score(self.best)
+
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_modules/Solid/ParticleSwarm.html b/docs/_modules/Solid/ParticleSwarm.html new file mode 100644 index 0000000..d148749 --- /dev/null +++ b/docs/_modules/Solid/ParticleSwarm.html @@ -0,0 +1,281 @@ + + + + + + + + Solid.ParticleSwarm — Solid 0.11 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for Solid.ParticleSwarm

+from abc import ABCMeta, abstractmethod
+from random import random
+from numpy import apply_along_axis, argmin, array, copy, diag_indices_from, dot, zeros
+from numpy.random import uniform
+
+
+
[docs]class ParticleSwarm: + """ + Conducts particle swarm optimization + """ + __metaclass__ = ABCMeta + + swarm_size = None + member_size = None + lower_bound = None + upper_bound = None + + pos = None + vel = None + scores = None + best = None + global_best = None + + c1 = None + c2 = None + c3 = None + + cur_steps = None + max_steps = None + min_objective = None + + def __init__(self, swarm_size, member_size, lower_bound, upper_bound, c1, c2, c3, + max_steps, min_objective=None): + """ + + :param swarm_size: number of members in swarm + :param member_size: number of components per member vector + :param lower_bound: list of lower bounds, where ith element is ith lower bound + :param upper_bound: list of upper bounds, where ith element is ith upper bound + :param c1: constant for 1st term in velocity calculation + :param c2: contsant for 2nd term in velocity calculation + :param c3: constant for 3rd term in velocity calculation + :param max_steps: maximum steps to run algorithm for + :param min_objective: objective function value to stop algorithm once reached + """ + if isinstance(swarm_size, int) and swarm_size > 0: + self.swarm_size = swarm_size + else: + raise ValueError('Swarm size must be a positive integer') + + if isinstance(member_size, int) and member_size > 0: + self.member_size = member_size + else: + raise ValueError('Member size must be a positive integer') + + if all([isinstance(x, (int, float)) for x in lower_bound]): + self.lower_bound = array([float(x) for x in lower_bound]) + else: + raise ValueError('Lower bounds must be numeric types') + + if all([isinstance(x, (int, float)) for x in upper_bound]): + self.upper_bound = array([float(x) for x in upper_bound]) + else: + raise ValueError('Upper bounds must be numeric types') + + self.pos = uniform(self.lower_bound, self.upper_bound, size=(swarm_size, member_size)) + + self.vel = uniform(self.lower_bound - self.upper_bound, self.upper_bound - self.lower_bound, size=(swarm_size, member_size)) + + self.best = copy(self.pos) + + if isinstance(c1, (int, float)) and isinstance(c2, (int, float)) and isinstance(c3, (int, float)): + self.c1 = float(c1) + self.c2 = float(c2) + self.c3 = float(c3) + else: + raise ValueError() + + if isinstance(max_steps, int): + self.max_steps = max_steps + else: + raise ValueError() + + if min_objective is not None: + if isinstance(min_objective, (int, float)): + self.min_objective = float(min_objective) + else: + raise ValueError() + + def __str__(self): + return ('PARTICLE SWARM: \n' + + 'CURRENT STEPS: %d \n' + + 'BEST FITNESS: %f \n' + + 'BEST MEMBER: %s \n\n') % \ + (self.cur_steps, self._objective(self.global_best[0]), str(self.global_best[0])) + + def __repr__(self): + return self.__str__() + + def _clear(self): + """ + Resets the variables that are altered on a per-run basis of the algorithm + + :return: None + """ + self.pos = uniform(self.lower_bound, self.upper_bound, size=(self.swarm_size, self.member_size)) + self.vel = uniform(self.lower_bound - self.upper_bound, self.upper_bound - self.lower_bound, size=(self.swarm_size, self.member_size)) + self.scores = self._score(self.pos) + self.best = copy(self.pos) + self.cur_steps = 0 + self._global_best() + + @abstractmethod + def _objective(self, member): + """ + Returns objective function value for a member of swarm - + operates on 1D numpy array + + :param member: a member + :return: objective function value of member + """ + pass + + def _score(self, pos): + """ + Applies objective function to all members of swarm + + :param pos: position matrix + :return: score vector + """ + return apply_along_axis(self._objective, 1, pos) + + def _best(self, old, new): + """ + Finds the best objective function values for each member of swarm + + :param old: old values + :param new: new values + :return: None + """ + old_scores = self._score(old) + new_scores = self._score(new) + best = [] + for i in range(len(old_scores)): + if old_scores[i] < new_scores[i]: + best.append(old[i]) + else: + best.append(new[i]) + self.best = array(best) + + def _global_best(self): + """ + Finds the global best across swarm + + :return: None + """ + if self.global_best is None or min(self.scores) < self._objective(self.global_best[0]): + self.global_best = array([self.pos[argmin(self.scores)],] * self.swarm_size) + +
[docs] def run(self, verbose=True): + """ + Conducts particle swarm optimization + + :param verbose: indicates whether or not to print progress regularly + :return: best member of swarm and objective function value of best member of swarm + """ + self._clear() + for i in range(self.max_steps): + self.cur_steps += 1 + + if ((i + 1) % 100 == 0) and verbose: + print self + + u1 = zeros((self.swarm_size, self.swarm_size)) + u1[diag_indices_from(u1)] = [random() for x in range(self.swarm_size)] + u2 = zeros((self.swarm_size, self.swarm_size)) + u2[diag_indices_from(u2)] = [random() for x in range(self.swarm_size)] + + vel_new = (self.c1 * self.vel) + \ + (self.c2 * dot(u1, (self.best - self.pos))) + \ + (self.c3 * dot(u2, (self.global_best - self.pos))) + + pos_new = self.pos + vel_new + + self._best(self.pos, pos_new) + self.pos = pos_new + self.scores = self._score(self.pos) + self._global_best() + + if self._objective(self.global_best[0]) < self.min_objective: + print "TERMINATING - REACHED MINIMUM OBJECTIVE" + return self.global_best[0], self._objective(self.global_best[0]) + print "TERMINATING - REACHED MAXIMUM STEPS" + return self.global_best[0], self._objective(self.global_best[0])
+
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_modules/Solid/SimulatedAnnealing.html b/docs/_modules/Solid/SimulatedAnnealing.html new file mode 100644 index 0000000..c70343b --- /dev/null +++ b/docs/_modules/Solid/SimulatedAnnealing.html @@ -0,0 +1,255 @@ + + + + + + + + Solid.SimulatedAnnealing — Solid 0.11 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for Solid.SimulatedAnnealing

+from abc import ABCMeta, abstractmethod
+from copy import deepcopy
+from math import exp
+from random import random
+
+
+
[docs]class SimulatedAnnealing: + """ + Conducts simulated annealing algorithm + """ + __metaclass__ = ABCMeta + + initial_state = None + current_state = None + best_state = None + + cur_steps = 0 + max_steps = None + + current_energy = None + best_energy = None + min_energy = None + + start_temp = None + current_temp = None + adjust_temp = None + + def _exponential(self, schedule_constant): + def f(): + self.current_temp *= schedule_constant + return f + + def _linear(self, schedule_constant): + def f(): + self.current_temp -= schedule_constant + return f + + def _get_schedule(self, schedule_str, schedule_constant): + if schedule_str == 'exponential': + return self._exponential(schedule_constant) + elif schedule_str == 'linear': + return self._linear(schedule_constant) + else: + raise ValueError('Annealing schedule must be either "exponential" or "linear"') + + def __init__(self, initial_state, temp_begin, schedule_constant, max_steps, + min_energy=None, schedule='exponential'): + """ + + :param initial_state: initial state of annealing algorithm + :param max_steps: maximum number of iterations to conduct annealing for + :param temp_begin: beginning temperature + :param schedule_constant: constant value in annealing schedule function + :param min_energy: energy value to stop algorithm once reached + :param schedule: 'exponential' or 'linear' annealing schedule + """ + self.initial_state = initial_state + + if isinstance(max_steps, int) and max_steps > 0: + self.max_steps = max_steps + else: + raise ValueError('Max steps must be a positive integer') + + if min_energy is not None: + if isinstance(min_energy, (float, int)): + self.min_energy = float(min_energy) + else: + raise ValueError('Minimum energy must be a numeric type') + + if isinstance(temp_begin, (float, int)): + self.start_temp = float(temp_begin) + else: + raise ValueError('Starting temperature must be a numeric type') + + self.adjust_temp = self._get_schedule(schedule, schedule_constant) + + def __str__(self): + return ('SIMULATED ANNEALING: \n' + + 'CURRENT STEPS: %d \n' + + 'CURRENT TEMPERATURE: %f \n' + + 'BEST ENERGY: %f \n' + + 'BEST STATE: %s \n\n') % \ + (self.cur_steps, self.current_temp, self.best_energy, str(self.best_state)) + + def __repr__(self): + return self.__str__() + + def _clear(self): + """ + Resets the variables that are altered on a per-run basis of the algorithm + + :return: None + """ + self.cur_steps = 0 + self.current_state = None + self.best_state = None + self.current_energy = None + self.best_energy = None + + @abstractmethod + def _neighbor(self): + """ + Returns a random member of the neighbor of the current state + + :return: a random neighbor, given access to self.current_state + """ + pass + + @abstractmethod + def _energy(self, state): + """ + Finds the energy of a given state + + :param state: a state + :return: energy of state + """ + pass + + def _accept_neighbor(self, neighbor): + """ + Probabilistically determines whether or not to accept a transition to a neighbor + + :param neighbor: a state + :return: boolean indicating whether or not transition is accepted + """ + try: + p = exp(-(self._energy(neighbor) - self._energy(self.current_state)) / self.current_temp) + except OverflowError: + return True + return True if p >= 1 else p >= random() + +
[docs] def run(self, verbose=True): + """ + Conducts simulated annealing + + :param verbose: indicates whether or not to print progress regularly + :return: best state and best energy + """ + self._clear() + self.current_state = self.initial_state + self.current_temp = self.start_temp + self.best_energy = self._energy(self.current_state) + for i in range(self.max_steps): + self.cur_steps += 1 + + if ((i + 1) % 100 == 0) and verbose: + print self + + neighbor = self._neighbor() + + if self._accept_neighbor(neighbor): + self.current_state = neighbor + self.current_energy = self._energy(self.current_state) + + if self.current_energy < self.best_energy: + self.best_energy = self.current_energy + self.best_state = deepcopy(self.current_state) + + if self.min_energy is not None and self.current_energy < self.min_energy: + print "TERMINATING - REACHED MINIMUM ENERGY" + return self.best_state, self.best_energy + + self.adjust_temp() + if self.current_temp < 0.000001: + print "TERMINATING - REACHED TEMPERATURE OF 0" + return self.best_state, self.best_energy + print "TERMINATING - REACHED MAXIMUM STEPS" + return self.best_state, self.best_energy
+
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_modules/Solid/StochasticHillClimb.html b/docs/_modules/Solid/StochasticHillClimb.html new file mode 100644 index 0000000..95573cb --- /dev/null +++ b/docs/_modules/Solid/StochasticHillClimb.html @@ -0,0 +1,219 @@ + + + + + + + + Solid.StochasticHillClimb — Solid 0.11 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for Solid.StochasticHillClimb

+from abc import ABCMeta, abstractmethod
+from copy import deepcopy
+from math import exp
+from random import random
+
+
+
[docs]class StochasticHillClimb: + """ + Conducts stochastic hill climb + """ + __metaclass__ = ABCMeta + + initial_state = None + current_state = None + best_state = None + + cur_steps = 0 + max_steps = None + + best_objective = None + max_objective = None + + temp = None + + def __init__(self, initial_state, temp, max_steps, max_objective=None): + """ + + :param initial_state: initial state of hill climbing + :param max_steps: maximum steps to run hill climbing for + :param temp: temperature in probabilistic acceptance of transition + :param max_objective: objective function to stop algorithm once reached + """ + self.initial_state = initial_state + + if isinstance(max_steps, int) and max_steps > 0: + self.max_steps = max_steps + else: + raise ValueError('Max steps must be a positive integer') + + if max_objective is not None: + if isinstance(max_objective, (float, int)): + self.max_objective = float(max_objective) + else: + raise ValueError('Maximum objective must be a numeric type') + + if isinstance(temp, (float, int)): + self.temp = float(temp) + else: + raise ValueError('Temperature must be a numeric type') + + def __str__(self): + return ('STOCHASTIC HILL CLIMB: \n' + + 'CURRENT STEPS: %d \n' + + 'BEST OBJECTIVE: %f \n' + + 'BEST STATE: %s \n\n') % \ + (self.cur_steps, self.best_objective, str(self.best_state)) + + def __repr__(self): + return self.__str__() + + def _clear(self): + """ + Resets the variables that are altered on a per-run basis of the algorithm + + :return: None + """ + self.cur_steps = 0 + self.current_state = None + self.best_state = None + self.best_objective = None + + @abstractmethod + def _neighbor(self): + """ + Returns a random member of the neighbor of the current state + + :return: a random neighbor, given access to self.current_state + """ + pass + + @abstractmethod + def _objective(self, state): + """ + Evaluates a given state + + :param state: a state + :return: objective function value of state + """ + pass + + def _accept_neighbor(self, neighbor): + """ + Probabilistically determines whether or not to accept a transition to a neighbor + + :param neighbor: a state + :return: boolean indicating whether or not transition was accepted + """ + try: + p = 1. / (1 + (exp((self._objective(self.current_state) - self._objective(neighbor)) / self.temp))) + except OverflowError: + return True + return True if p >= 1 else p >= random() + +
[docs] def run(self, verbose=True): + """ + Conducts hill climb + + :param verbose: indicates whether or not to print progress regularly + :return: best state and best objective function value + """ + self._clear() + self.current_state = self.initial_state + for i in range(self.max_steps): + self.cur_steps += 1 + + if ((i + 1) % 100 == 0) and verbose: + print self + + neighbor = self._neighbor() + + if self._accept_neighbor(neighbor): + self.current_state = neighbor + + if self._objective(self.current_state) > self.best_objective: + self.best_objective = self._objective(self.current_state) + self.best_state = deepcopy(self.current_state) + + if self.max_objective is not None and self.best_objective > self.max_objective: + print "TERMINATING - REACHED MAXIMUM OBJECTIVE" + return self.best_state, self.best_objective + print "TERMINATING - REACHED MAXIMUM STEPS" + return self.best_state, self.best_objective
+
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_modules/Solid/TabuSearch.html b/docs/_modules/Solid/TabuSearch.html new file mode 100644 index 0000000..ea3d05f --- /dev/null +++ b/docs/_modules/Solid/TabuSearch.html @@ -0,0 +1,227 @@ + + + + + + + + Solid.TabuSearch — Solid 0.11 documentation + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +

Source code for Solid.TabuSearch

+from abc import ABCMeta, abstractmethod
+from copy import deepcopy
+from random import randint, random, shuffle
+from collections import deque
+from numpy import argmax
+
+
[docs]class TabuSearch: + """ + Conducts tabu search + """ + __metaclass__ = ABCMeta + + cur_steps = None + + tabu_size = None + tabu_list = None + + initial_state = None + current = None + best = None + + max_steps = None + max_score = None + + def __init__(self, initial_state, tabu_size, max_steps, max_score=None): + """ + + :param initial_state: initial state, should implement __eq__ or __cmp__ + :param tabu_size: number of states to keep in tabu list + :param max_steps: maximum number of steps to run algorithm for + :param max_score: score to stop algorithm once reached + """ + self.initial_state = initial_state + + if isinstance(tabu_size, int) and tabu_size > 0: + self.tabu_size = tabu_size + else: + raise TypeError('Tabu size must be a positive integer') + + if isinstance(max_steps, int) and max_steps > 0: + self.max_steps = max_steps + else: + raise TypeError('Maximum steps must be a positive integer') + + if max_score is not None: + if isinstance(max_score, (int, float)): + self.max_score = float(max_score) + else: + raise TypeError('Maximum score must be a numeric type') + + def __str__(self): + return ('TABU SEARCH: \n' + + 'CURRENT STEPS: %d \n' + + 'BEST SCORE: %f \n' + + 'BEST MEMBER: %s \n\n') % \ + (self.cur_steps, self._score(self.best), str(self.best)) + + def __repr__(self): + return self.__str__() + + def _clear(self): + """ + Resets the variables that are altered on a per-run basis of the algorithm + + :return: None + """ + self.cur_steps = 0 + self.tabu_list = deque(maxlen=self.tabu_size) + self.current = self.initial_state + self.best = self.initial_state + + @abstractmethod + def _score(self, state): + """ + Returns objective function value of a state + + :param state: a state + :return: objective function value of state + """ + pass + + @abstractmethod + def _neighborhood(self): + """ + Returns list of all members of neighborhood of current state, given self.current + + :return: list of members of neighborhood + """ + pass + + def _best(self, neighborhood): + """ + Finds the best member of a neighborhood + + :param neighborhood: a neighborhood + :return: best member of neighborhood + """ + return neighborhood[argmax([self._score(x) for x in neighborhood])] + +
[docs] def run(self, verbose=True): + """ + Conducts tabu search + + :param verbose: indicates whether or not to print progress regularly + :return: best state and objective function value of best state + """ + self._clear() + for i in range(self.max_steps): + self.cur_steps += 1 + + if ((i + 1) % 100 == 0) and verbose: + print self + + neighborhood = self._neighborhood() + neighborhood_best = self._best(neighborhood) + + while True: + if all([x in self.tabu_list for x in neighborhood]): + print "TERMINATING - NO SUITABLE NEIGHBORS" + return self.best, self._score(self.best) + if neighborhood_best in self.tabu_list: + if self._score(neighborhood_best) > self._score(self.best): + self.tabu_list.append(neighborhood_best) + self.best = deepcopy(neighborhood_best) + break + else: + neighborhood.remove(neighborhood_best) + neighborhood_best = self._best(neighborhood) + else: + self.tabu_list.append(neighborhood_best) + self.current = neighborhood_best + if self._score(self.current) > self._score(self.best): + self.best = deepcopy(self.current) + break + + if self.max_score is not None and self._score(self.best) > self.max_score: + print "TERMINATING - REACHED MAXIMUM SCORE" + return self.best, self._score(self.best) + print "TERMINATING - REACHED MAXIMUM STEPS" + return self.best, self._score(self.best)
+
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_modules/index.html b/docs/_modules/index.html new file mode 100644 index 0000000..9754ad8 --- /dev/null +++ b/docs/_modules/index.html @@ -0,0 +1,92 @@ + + + + + + + + Overview: module code — Solid 0.11 documentation + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/docs/_sources/Solid.rst.txt b/docs/_sources/Solid.rst.txt new file mode 100644 index 0000000..f405b79 --- /dev/null +++ b/docs/_sources/Solid.rst.txt @@ -0,0 +1,70 @@ +Solid package +============= + +Submodules +---------- + +Solid\.EvolutionaryAlgorithm module +----------------------------------- + +.. automodule:: Solid.EvolutionaryAlgorithm + :members: + :undoc-members: + :show-inheritance: + +Solid\.GeneticAlgorithm module +------------------------------ + +.. automodule:: Solid.GeneticAlgorithm + :members: + :undoc-members: + :show-inheritance: + +Solid\.HarmonySearch module +--------------------------- + +.. automodule:: Solid.HarmonySearch + :members: + :undoc-members: + :show-inheritance: + +Solid\.ParticleSwarm module +--------------------------- + +.. automodule:: Solid.ParticleSwarm + :members: + :undoc-members: + :show-inheritance: + +Solid\.SimulatedAnnealing module +-------------------------------- + +.. automodule:: Solid.SimulatedAnnealing + :members: + :undoc-members: + :show-inheritance: + +Solid\.StochasticHillClimb module +--------------------------------- + +.. automodule:: Solid.StochasticHillClimb + :members: + :undoc-members: + :show-inheritance: + +Solid\.TabuSearch module +------------------------ + +.. automodule:: Solid.TabuSearch + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: Solid + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/_sources/index.rst.txt b/docs/_sources/index.rst.txt new file mode 100644 index 0000000..2d758fd --- /dev/null +++ b/docs/_sources/index.rst.txt @@ -0,0 +1,20 @@ +.. Solid documentation master file, created by + sphinx-quickstart on Mon Jun 19 19:02:57 2017. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Solid's documentation! +================================= + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/_sources/modules.rst.txt b/docs/_sources/modules.rst.txt new file mode 100644 index 0000000..a94e0c1 --- /dev/null +++ b/docs/_sources/modules.rst.txt @@ -0,0 +1,7 @@ +Solid +===== + +.. toctree:: + :maxdepth: 4 + + Solid diff --git a/docs/_static/ajax-loader.gif b/docs/_static/ajax-loader.gif new file mode 100644 index 0000000..61faf8c Binary files /dev/null and b/docs/_static/ajax-loader.gif differ diff --git a/docs/_static/alabaster.css b/docs/_static/alabaster.css new file mode 100644 index 0000000..be65b13 --- /dev/null +++ b/docs/_static/alabaster.css @@ -0,0 +1,693 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro', serif; + font-size: 17px; + background-color: #fff; + color: #000; + margin: 0; + padding: 0; +} + + +div.document { + width: 940px; + margin: 30px auto 0 auto; +} + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 220px; +} + +div.sphinxsidebar { + width: 220px; + font-size: 14px; + line-height: 1.5; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.body { + background-color: #fff; + color: #3E4349; + padding: 0 30px 0 30px; +} + +div.body > .section { + text-align: left; +} + +div.footer { + width: 940px; + margin: 20px auto 30px auto; + font-size: 14px; + color: #888; + text-align: right; +} + +div.footer a { + color: #888; +} + +p.caption { + font-family: inherit; + font-size: inherit; +} + + +div.relations { + display: none; +} + + +div.sphinxsidebar a { + color: #444; + text-decoration: none; + border-bottom: 1px dotted #999; +} + +div.sphinxsidebar a:hover { + border-bottom: 1px solid #999; +} + +div.sphinxsidebarwrapper { + padding: 18px 10px; +} + +div.sphinxsidebarwrapper p.logo { + padding: 0; + margin: -10px 0 0 0px; + text-align: center; +} + +div.sphinxsidebarwrapper h1.logo { + margin-top: -10px; + text-align: center; + margin-bottom: 5px; + text-align: left; +} + +div.sphinxsidebarwrapper h1.logo-name { + margin-top: 0px; +} + +div.sphinxsidebarwrapper p.blurb { + margin-top: 0; + font-style: normal; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: 'Garamond', 'Georgia', serif; + color: #444; + font-size: 24px; + font-weight: normal; + margin: 0 0 5px 0; + padding: 0; +} + +div.sphinxsidebar h4 { + font-size: 20px; +} + +div.sphinxsidebar h3 a { + color: #444; +} + +div.sphinxsidebar p.logo a, +div.sphinxsidebar h3 a, +div.sphinxsidebar p.logo a:hover, +div.sphinxsidebar h3 a:hover { + border: none; +} + +div.sphinxsidebar p { + color: #555; + margin: 10px 0; +} + +div.sphinxsidebar ul { + margin: 10px 0; + padding: 0; + color: #000; +} + +div.sphinxsidebar ul li.toctree-l1 > a { + font-size: 120%; +} + +div.sphinxsidebar ul li.toctree-l2 > a { + font-size: 110%; +} + +div.sphinxsidebar input { + border: 1px solid #CCC; + font-family: 'goudy old style', 'minion pro', 'bell mt', Georgia, 'Hiragino Mincho Pro', serif; + font-size: 1em; +} + +div.sphinxsidebar hr { + border: none; + height: 1px; + color: #AAA; + background: #AAA; + + text-align: left; + margin-left: 0; + width: 50%; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #004B6B; + text-decoration: underline; +} + +a:hover { + color: #6D4100; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: 'Garamond', 'Georgia', serif; + font-weight: normal; + margin: 30px 0px 10px 0px; + padding: 0; +} + +div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } +div.body h2 { font-size: 180%; } +div.body h3 { font-size: 150%; } +div.body h4 { font-size: 130%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #DDD; + padding: 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + color: #444; + background: #EAEAEA; +} + +div.body p, div.body dd, div.body li { + line-height: 1.4em; +} + +div.admonition { + margin: 20px 0px; + padding: 10px 30px; + background-color: #EEE; + border: 1px solid #CCC; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fafafa; +} + +div.admonition p.admonition-title { + font-family: 'Garamond', 'Georgia', serif; + font-weight: normal; + font-size: 24px; + margin: 0 0 10px 0; + padding: 0; + line-height: 1; +} + +div.admonition p.last { + margin-bottom: 0; +} + +div.highlight { + background-color: #fff; +} + +dt:target, .highlight { + background: #FAF3E8; +} + +div.warning { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.danger { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.error { + background-color: #FCC; + border: 1px solid #FAA; + -moz-box-shadow: 2px 2px 4px #D52C2C; + -webkit-box-shadow: 2px 2px 4px #D52C2C; + box-shadow: 2px 2px 4px #D52C2C; +} + +div.caution { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.attention { + background-color: #FCC; + border: 1px solid #FAA; +} + +div.important { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.note { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.tip { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.hint { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.seealso { + background-color: #EEE; + border: 1px solid #CCC; +} + +div.topic { + background-color: #EEE; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre, tt, code { + font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; + font-size: 0.9em; +} + +.hll { + background-color: #FFC; + margin: 0 -12px; + padding: 0 12px; + display: block; +} + +img.screenshot { +} + +tt.descname, tt.descclassname, code.descname, code.descclassname { + font-size: 0.95em; +} + +tt.descname, code.descname { + padding-right: 0.08em; +} + +img.screenshot { + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils { + border: 1px solid #888; + -moz-box-shadow: 2px 2px 4px #EEE; + -webkit-box-shadow: 2px 2px 4px #EEE; + box-shadow: 2px 2px 4px #EEE; +} + +table.docutils td, table.docutils th { + border: 1px solid #888; + padding: 0.25em 0.7em; +} + +table.field-list, table.footnote { + border: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} + +table.footnote { + margin: 15px 0; + width: 100%; + border: 1px solid #EEE; + background: #FDFDFD; + font-size: 0.9em; +} + +table.footnote + table.footnote { + margin-top: -15px; + border-top: none; +} + +table.field-list th { + padding: 0 0.8em 0 0; +} + +table.field-list td { + padding: 0; +} + +table.field-list p { + margin-bottom: 0.8em; +} + +/* Cloned from + * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 + */ +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +table.footnote td.label { + width: .1px; + padding: 0.3em 0 0.3em 0.5em; +} + +table.footnote td { + padding: 0.3em 0.5em; +} + +dl { + margin: 0; + padding: 0; +} + +dl dd { + margin-left: 30px; +} + +blockquote { + margin: 0 0 0 30px; + padding: 0; +} + +ul, ol { + /* Matches the 30px from the narrow-screen "li > ul" selector below */ + margin: 10px 0 10px 30px; + padding: 0; +} + +pre { + background: #EEE; + padding: 7px 30px; + margin: 15px 0px; + line-height: 1.3em; +} + +div.viewcode-block:target { + background: #ffd; +} + +dl pre, blockquote pre, li pre { + margin-left: 0; + padding-left: 30px; +} + +tt, code { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ +} + +tt.xref, code.xref, a tt { + background-color: #FBFBFB; + border-bottom: 1px solid #fff; +} + +a.reference { + text-decoration: none; + border-bottom: 1px dotted #004B6B; +} + +/* Don't put an underline on images */ +a.image-reference, a.image-reference:hover { + border-bottom: none; +} + +a.reference:hover { + border-bottom: 1px solid #6D4100; +} + +a.footnote-reference { + text-decoration: none; + font-size: 0.7em; + vertical-align: top; + border-bottom: 1px dotted #004B6B; +} + +a.footnote-reference:hover { + border-bottom: 1px solid #6D4100; +} + +a:hover tt, a:hover code { + background: #EEE; +} + + +@media screen and (max-width: 870px) { + + div.sphinxsidebar { + display: none; + } + + div.document { + width: 100%; + + } + + div.documentwrapper { + margin-left: 0; + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + } + + div.bodywrapper { + margin-top: 0; + margin-right: 0; + margin-bottom: 0; + margin-left: 0; + } + + ul { + margin-left: 0; + } + + li > ul { + /* Matches the 30px from the "ul, ol" selector above */ + margin-left: 30px; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .bodywrapper { + margin: 0; + } + + .footer { + width: auto; + } + + .github { + display: none; + } + + + +} + + + +@media screen and (max-width: 875px) { + + body { + margin: 0; + padding: 20px 30px; + } + + div.documentwrapper { + float: none; + background: #fff; + } + + div.sphinxsidebar { + display: block; + float: none; + width: 102.5%; + margin: 50px -30px -20px -30px; + padding: 10px 20px; + background: #333; + color: #FFF; + } + + div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, + div.sphinxsidebar h3 a { + color: #fff; + } + + div.sphinxsidebar a { + color: #AAA; + } + + div.sphinxsidebar p.logo { + display: none; + } + + div.document { + width: 100%; + margin: 0; + } + + div.footer { + display: none; + } + + div.bodywrapper { + margin: 0; + } + + div.body { + min-height: 0; + padding: 0; + } + + .rtd_doc_footer { + display: none; + } + + .document { + width: auto; + } + + .footer { + width: auto; + } + + .footer { + width: auto; + } + + .github { + display: none; + } +} + + +/* misc. */ + +.revsys-inline { + display: none!important; +} + +/* Make nested-list/multi-paragraph items look better in Releases changelog + * pages. Without this, docutils' magical list fuckery causes inconsistent + * formatting between different release sub-lists. + */ +div#changelog > div.section > ul > li > p:only-child { + margin-bottom: 0; +} + +/* Hide fugly table cell borders in ..bibliography:: directive output */ +table.docutils.citation, table.docutils.citation td, table.docutils.citation th { + border: none; + /* Below needed in some edge cases; if not applied, bottom shadows appear */ + -moz-box-shadow: none; + -webkit-box-shadow: none; + box-shadow: none; +} \ No newline at end of file diff --git a/docs/_static/basic.css b/docs/_static/basic.css new file mode 100644 index 0000000..6df76b0 --- /dev/null +++ b/docs/_static/basic.css @@ -0,0 +1,639 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox input[type="text"] { + width: 170px; +} + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlighted { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +div.code-block-caption { + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +div.code-block-caption + div > div.highlight > pre { + margin-top: 0; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + padding: 1em 1em 0; +} + +div.literal-block-wrapper div.highlight { + margin: 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: relative; + left: 0px; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/_static/comment-bright.png b/docs/_static/comment-bright.png new file mode 100644 index 0000000..15e27ed Binary files /dev/null and b/docs/_static/comment-bright.png differ diff --git a/docs/_static/comment-close.png b/docs/_static/comment-close.png new file mode 100644 index 0000000..4d91bcf Binary files /dev/null and b/docs/_static/comment-close.png differ diff --git a/docs/_static/comment.png b/docs/_static/comment.png new file mode 100644 index 0000000..dfbc0cb Binary files /dev/null and b/docs/_static/comment.png differ diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 0000000..2a924f1 --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1 @@ +/* This file intentionally left blank. */ diff --git a/docs/_static/doctools.js b/docs/_static/doctools.js new file mode 100644 index 0000000..5654977 --- /dev/null +++ b/docs/_static/doctools.js @@ -0,0 +1,287 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + */ +jQuery.urldecode = function(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s == 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node) { + if (node.nodeType == 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this); + }); + } + } + return this.each(function() { + highlight(this); + }); +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated == 'undefined') + return string; + return (typeof translated == 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated == 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) == 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this == '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); \ No newline at end of file diff --git a/docs/_static/down-pressed.png b/docs/_static/down-pressed.png new file mode 100644 index 0000000..5756c8c Binary files /dev/null and b/docs/_static/down-pressed.png differ diff --git a/docs/_static/down.png b/docs/_static/down.png new file mode 100644 index 0000000..1b3bdad Binary files /dev/null and b/docs/_static/down.png differ diff --git a/docs/_static/file.png b/docs/_static/file.png new file mode 100644 index 0000000..a858a41 Binary files /dev/null and b/docs/_static/file.png differ diff --git a/docs/_static/jquery-3.1.0.js b/docs/_static/jquery-3.1.0.js new file mode 100644 index 0000000..f2fc274 --- /dev/null +++ b/docs/_static/jquery-3.1.0.js @@ -0,0 +1,10074 @@ +/*eslint-disable no-unused-vars*/ +/*! + * jQuery JavaScript Library v3.1.0 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2016-07-07T21:44Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var document = window.document; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + + + + function DOMEval( code, doc ) { + doc = doc || document; + + var script = doc.createElement( "script" ); + + script.text = code; + doc.head.appendChild( script ).parentNode.removeChild( script ); + } +/* global Symbol */ +// Defining this global in .eslintrc would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.1.0", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android <=4.0 only + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num != null ? + + // Return just the one element from the set + ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + + // Return all the elements in a clean array + slice.call( this ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = jQuery.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isArray: Array.isArray, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // As of jQuery 3.0, isNumeric is limited to + // strings and numbers (primitives or objects) + // that can be coerced to finite numbers (gh-2662) + var type = jQuery.type( obj ); + return ( type === "number" || type === "string" ) && + + // parseFloat NaNs numeric-cast false positives ("") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + !isNaN( obj - parseFloat( obj ) ); + }, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + + /* eslint-disable no-unused-vars */ + // See https://github.com/eslint/eslint/issues/6125 + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + DOMEval( code ); + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE <=9 - 11, Edge 12 - 13 + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android <=4.0 only + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.0 + * https://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-01-04 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + disabledAncestor = addCombinator( + function( elem ) { + return elem.disabled === true; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[i] = "#" + nid + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement("fieldset"); + + try { + return !!fn( el ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + // Known :disabled false positives: + // IE: *[disabled]:not(button, input, select, textarea, optgroup, option, menuitem, fieldset) + // not IE: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Check form elements and option elements for explicit disabling + return "label" in elem && elem.disabled === disabled || + "form" in elem && elem.disabled === disabled || + + // Check non-disabled form elements for fieldset[disabled] ancestors + "form" in elem && elem.disabled === false && ( + // Support: IE6-11+ + // Ancestry is covered for us + elem.isDisabled === disabled || + + // Otherwise, assume any non-