summaryrefslogtreecommitdiffstats
path: root/contrib/python/kiwisolver
diff options
context:
space:
mode:
authorshumkovnd <[email protected]>2023-11-10 14:39:34 +0300
committershumkovnd <[email protected]>2023-11-10 16:42:24 +0300
commit77eb2d3fdcec5c978c64e025ced2764c57c00285 (patch)
treec51edb0748ca8d4a08d7c7323312c27ba1a8b79a /contrib/python/kiwisolver
parentdd6d20cadb65582270ac23f4b3b14ae189704b9d (diff)
KIKIMR-19287: add task_stats_drawing script
Diffstat (limited to 'contrib/python/kiwisolver')
-rw-r--r--contrib/python/kiwisolver/py2/.dist-info/METADATA42
-rw-r--r--contrib/python/kiwisolver/py2/.dist-info/top_level.txt1
-rw-r--r--contrib/python/kiwisolver/py2/README.rst19
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/AssocVector.h354
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/constraint.h124
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/debug.h203
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/errors.h188
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/expression.h57
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/kiwi.h19
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/maptype.h38
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/row.h192
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/shareddata.h157
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/solver.h178
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/solverimpl.h840
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/strength.h44
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/symbol.h68
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/symbolics.h685
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/term.h51
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/util.h25
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/variable.h121
-rw-r--r--contrib/python/kiwisolver/py2/kiwi/version.h14
-rw-r--r--contrib/python/kiwisolver/py2/py/constraint.cpp299
-rw-r--r--contrib/python/kiwisolver/py2/py/expression.cpp326
-rw-r--r--contrib/python/kiwisolver/py2/py/kiwisolver.cpp86
-rw-r--r--contrib/python/kiwisolver/py2/py/pythonhelpers.h771
-rw-r--r--contrib/python/kiwisolver/py2/py/solver.cpp333
-rw-r--r--contrib/python/kiwisolver/py2/py/strength.cpp162
-rw-r--r--contrib/python/kiwisolver/py2/py/symbolics.h620
-rw-r--r--contrib/python/kiwisolver/py2/py/term.cpp298
-rw-r--r--contrib/python/kiwisolver/py2/py/types.h112
-rw-r--r--contrib/python/kiwisolver/py2/py/util.h230
-rw-r--r--contrib/python/kiwisolver/py2/py/variable.cpp353
-rw-r--r--contrib/python/kiwisolver/py2/ya.make41
-rw-r--r--contrib/python/kiwisolver/py3/.dist-info/METADATA42
-rw-r--r--contrib/python/kiwisolver/py3/.dist-info/top_level.txt1
-rw-r--r--contrib/python/kiwisolver/py3/README.rst19
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/AssocVector.h354
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/constraint.h124
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/debug.h203
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/errors.h188
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/expression.h57
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/kiwi.h19
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/maptype.h38
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/row.h192
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/shareddata.h157
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/solver.h178
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/solverimpl.h840
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/strength.h44
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/symbol.h68
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/symbolics.h685
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/term.h51
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/util.h25
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/variable.h121
-rw-r--r--contrib/python/kiwisolver/py3/kiwi/version.h14
-rw-r--r--contrib/python/kiwisolver/py3/py/constraint.cpp299
-rw-r--r--contrib/python/kiwisolver/py3/py/expression.cpp326
-rw-r--r--contrib/python/kiwisolver/py3/py/kiwisolver.cpp86
-rw-r--r--contrib/python/kiwisolver/py3/py/pythonhelpers.h771
-rw-r--r--contrib/python/kiwisolver/py3/py/solver.cpp333
-rw-r--r--contrib/python/kiwisolver/py3/py/strength.cpp162
-rw-r--r--contrib/python/kiwisolver/py3/py/symbolics.h620
-rw-r--r--contrib/python/kiwisolver/py3/py/term.cpp298
-rw-r--r--contrib/python/kiwisolver/py3/py/types.h112
-rw-r--r--contrib/python/kiwisolver/py3/py/util.h230
-rw-r--r--contrib/python/kiwisolver/py3/py/variable.cpp353
-rw-r--r--contrib/python/kiwisolver/py3/ya.make41
-rw-r--r--contrib/python/kiwisolver/ya.make18
67 files changed, 14120 insertions, 0 deletions
diff --git a/contrib/python/kiwisolver/py2/.dist-info/METADATA b/contrib/python/kiwisolver/py2/.dist-info/METADATA
new file mode 100644
index 00000000000..6c363cae42f
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/.dist-info/METADATA
@@ -0,0 +1,42 @@
+Metadata-Version: 2.1
+Name: kiwisolver
+Version: 1.1.0
+Summary: A fast implementation of the Cassowary constraint solver
+Home-page: https://github.com/nucleic/kiwi
+Author: The Nucleic Development Team
+Author-email: [email protected]
+License: BSD
+Platform: UNKNOWN
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
+Requires-Dist: setuptools
+
+Welcome to Kiwi
+===============
+
+.. image:: https://travis-ci.org/nucleic/kiwi.svg?branch=master
+ :target: https://travis-ci.org/nucleic/kiwi
+.. image:: https://codecov.io/gh/nucleic/kiwi/branch/master/graph/badge.svg
+ :target: https://codecov.io/gh/nucleic/kiwi
+.. image:: https://readthedocs.org/projects/kiwisolver/badge/?version=latest
+ :target: https://kiwisolver.readthedocs.io/en/latest/?badge=latest
+ :alt: Documentation Status
+
+Kiwi is an efficient C++ implementation of the Cassowary constraint solving
+algorithm. Kiwi is an implementation of the algorithm based on the seminal
+Cassowary paper. It is *not* a refactoring of the original C++ solver. Kiwi
+has been designed from the ground up to be lightweight and fast. Kiwi ranges
+from 10x to 500x faster than the original Cassowary solver with typical use
+cases gaining a 40x improvement. Memory savings are consistently > 5x.
+
+In addition to the C++ solver, Kiwi ships with hand-rolled Python bindings.
+
+
diff --git a/contrib/python/kiwisolver/py2/.dist-info/top_level.txt b/contrib/python/kiwisolver/py2/.dist-info/top_level.txt
new file mode 100644
index 00000000000..9b85884d1a9
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/.dist-info/top_level.txt
@@ -0,0 +1 @@
+kiwisolver
diff --git a/contrib/python/kiwisolver/py2/README.rst b/contrib/python/kiwisolver/py2/README.rst
new file mode 100644
index 00000000000..4faa3c329ba
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/README.rst
@@ -0,0 +1,19 @@
+Welcome to Kiwi
+===============
+
+.. image:: https://travis-ci.org/nucleic/kiwi.svg?branch=master
+ :target: https://travis-ci.org/nucleic/kiwi
+.. image:: https://codecov.io/gh/nucleic/kiwi/branch/master/graph/badge.svg
+ :target: https://codecov.io/gh/nucleic/kiwi
+.. image:: https://readthedocs.org/projects/kiwisolver/badge/?version=latest
+ :target: https://kiwisolver.readthedocs.io/en/latest/?badge=latest
+ :alt: Documentation Status
+
+Kiwi is an efficient C++ implementation of the Cassowary constraint solving
+algorithm. Kiwi is an implementation of the algorithm based on the seminal
+Cassowary paper. It is *not* a refactoring of the original C++ solver. Kiwi
+has been designed from the ground up to be lightweight and fast. Kiwi ranges
+from 10x to 500x faster than the original Cassowary solver with typical use
+cases gaining a 40x improvement. Memory savings are consistently > 5x.
+
+In addition to the C++ solver, Kiwi ships with hand-rolled Python bindings.
diff --git a/contrib/python/kiwisolver/py2/kiwi/AssocVector.h b/contrib/python/kiwisolver/py2/kiwi/AssocVector.h
new file mode 100644
index 00000000000..0d5eb288efc
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/AssocVector.h
@@ -0,0 +1,354 @@
+////////////////////////////////////////////////////////////////////////////////
+// The Loki Library
+// Copyright (c) 2001 by Andrei Alexandrescu
+// This code accompanies the book:
+// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
+// Patterns Applied". Copyright (c) 2001. Addison-Wesley.
+// Permission to use, copy, modify, distribute and sell this software for any
+// purpose is hereby granted without fee, provided that the above copyright
+// notice appear in all copies and that both that copyright notice and this
+// permission notice appear in supporting documentation.
+// The author or Addison-Wesley Longman make no representations about the
+// suitability of this software for any purpose. It is provided "as is"
+// without express or implied warranty.
+////////////////////////////////////////////////////////////////////////////////
+#pragma once
+
+// $Id: AssocVector.h 765 2006-10-18 13:55:32Z syntheticpp $
+
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include <utility>
+
+namespace Loki
+{
+////////////////////////////////////////////////////////////////////////////////
+// class template AssocVectorCompare
+// Used by AssocVector
+////////////////////////////////////////////////////////////////////////////////
+
+ namespace Private
+ {
+ template <class Value, class C>
+ class AssocVectorCompare : public C
+ {
+ typedef std::pair<typename C::first_argument_type, Value>
+ Data;
+ typedef typename C::first_argument_type first_argument_type;
+
+ public:
+ AssocVectorCompare()
+ {}
+
+ AssocVectorCompare(const C& src) : C(src)
+ {}
+
+ bool operator()(const first_argument_type& lhs,
+ const first_argument_type& rhs) const
+ { return C::operator()(lhs, rhs); }
+
+ bool operator()(const Data& lhs, const Data& rhs) const
+ { return operator()(lhs.first, rhs.first); }
+
+ bool operator()(const Data& lhs,
+ const first_argument_type& rhs) const
+ { return operator()(lhs.first, rhs); }
+
+ bool operator()(const first_argument_type& lhs,
+ const Data& rhs) const
+ { return operator()(lhs, rhs.first); }
+ };
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+// class template AssocVector
+// An associative vector built as a syntactic drop-in replacement for std::map
+// BEWARE: AssocVector doesn't respect all map's guarantees, the most important
+// being:
+// * iterators are invalidated by insert and erase operations
+// * the complexity of insert/erase is O(N) not O(log N)
+// * value_type is std::pair<K, V> not std::pair<const K, V>
+// * iterators are random
+////////////////////////////////////////////////////////////////////////////////
+
+
+ template
+ <
+ class K,
+ class V,
+ class C = std::less<K>,
+ class A = std::allocator< std::pair<K, V> >
+ >
+ class AssocVector
+ : private std::vector< std::pair<K, V>, A >
+ , private Private::AssocVectorCompare<V, C>
+ {
+ typedef std::vector<std::pair<K, V>, A> Base;
+ typedef Private::AssocVectorCompare<V, C> MyCompare;
+
+ public:
+ typedef K key_type;
+ typedef V mapped_type;
+ typedef typename Base::value_type value_type;
+
+ typedef C key_compare;
+ typedef A allocator_type;
+ typedef typename A::reference reference;
+ typedef typename A::const_reference const_reference;
+ typedef typename Base::iterator iterator;
+ typedef typename Base::const_iterator const_iterator;
+ typedef typename Base::size_type size_type;
+ typedef typename Base::difference_type difference_type;
+ typedef typename A::pointer pointer;
+ typedef typename A::const_pointer const_pointer;
+ typedef typename Base::reverse_iterator reverse_iterator;
+ typedef typename Base::const_reverse_iterator const_reverse_iterator;
+
+ class value_compare
+ : public std::binary_function<value_type, value_type, bool>
+ , private key_compare
+ {
+ friend class AssocVector;
+
+ protected:
+ value_compare(key_compare pred) : key_compare(pred)
+ {}
+
+ public:
+ bool operator()(const value_type& lhs, const value_type& rhs) const
+ { return key_compare::operator()(lhs.first, rhs.first); }
+ };
+
+ // 23.3.1.1 construct/copy/destroy
+
+ explicit AssocVector(const key_compare& comp = key_compare(),
+ const A& alloc = A())
+ : Base(alloc), MyCompare(comp)
+ {}
+
+ template <class InputIterator>
+ AssocVector(InputIterator first, InputIterator last,
+ const key_compare& comp = key_compare(),
+ const A& alloc = A())
+ : Base(first, last, alloc), MyCompare(comp)
+ {
+ MyCompare& me = *this;
+ std::sort(begin(), end(), me);
+ }
+
+ AssocVector& operator=(const AssocVector& rhs)
+ {
+ AssocVector(rhs).swap(*this);
+ return *this;
+ }
+
+ // iterators:
+ // The following are here because MWCW gets 'using' wrong
+ iterator begin() { return Base::begin(); }
+ const_iterator begin() const { return Base::begin(); }
+ iterator end() { return Base::end(); }
+ const_iterator end() const { return Base::end(); }
+ reverse_iterator rbegin() { return Base::rbegin(); }
+ const_reverse_iterator rbegin() const { return Base::rbegin(); }
+ reverse_iterator rend() { return Base::rend(); }
+ const_reverse_iterator rend() const { return Base::rend(); }
+
+ // capacity:
+ bool empty() const { return Base::empty(); }
+ size_type size() const { return Base::size(); }
+ size_type max_size() { return Base::max_size(); }
+
+ // 23.3.1.2 element access:
+ mapped_type& operator[](const key_type& key)
+ { return insert(value_type(key, mapped_type())).first->second; }
+
+ // modifiers:
+ std::pair<iterator, bool> insert(const value_type& val)
+ {
+ bool found(true);
+ iterator i(lower_bound(val.first));
+
+ if (i == end() || this->operator()(val.first, i->first))
+ {
+ i = Base::insert(i, val);
+ found = false;
+ }
+ return std::make_pair(i, !found);
+ }
+ //Section [23.1.2], Table 69
+ //http://developer.apple.com/documentation/DeveloperTools/gcc-3.3/libstdc++/23_containers/howto.html#4
+ iterator insert(iterator pos, const value_type& val)
+ {
+ if( (pos == begin() || this->operator()(*(pos-1),val)) &&
+ (pos == end() || this->operator()(val, *pos)) )
+ {
+ return Base::insert(pos, val);
+ }
+ return insert(val).first;
+ }
+
+ template <class InputIterator>
+ void insert(InputIterator first, InputIterator last)
+ { for (; first != last; ++first) insert(*first); }
+
+ void erase(iterator pos)
+ { Base::erase(pos); }
+
+ size_type erase(const key_type& k)
+ {
+ iterator i(find(k));
+ if (i == end()) return 0;
+ erase(i);
+ return 1;
+ }
+
+ void erase(iterator first, iterator last)
+ { Base::erase(first, last); }
+
+ void swap(AssocVector& other)
+ {
+ Base::swap(other);
+ MyCompare& me = *this;
+ MyCompare& rhs = other;
+ std::swap(me, rhs);
+ }
+
+ void clear()
+ { Base::clear(); }
+
+ // observers:
+ key_compare key_comp() const
+ { return *this; }
+
+ value_compare value_comp() const
+ {
+ const key_compare& comp = *this;
+ return value_compare(comp);
+ }
+
+ // 23.3.1.3 map operations:
+ iterator find(const key_type& k)
+ {
+ iterator i(lower_bound(k));
+ if (i != end() && this->operator()(k, i->first))
+ {
+ i = end();
+ }
+ return i;
+ }
+
+ const_iterator find(const key_type& k) const
+ {
+ const_iterator i(lower_bound(k));
+ if (i != end() && this->operator()(k, i->first))
+ {
+ i = end();
+ }
+ return i;
+ }
+
+ size_type count(const key_type& k) const
+ { return find(k) != end(); }
+
+ iterator lower_bound(const key_type& k)
+ {
+ MyCompare& me = *this;
+ return std::lower_bound(begin(), end(), k, me);
+ }
+
+ const_iterator lower_bound(const key_type& k) const
+ {
+ const MyCompare& me = *this;
+ return std::lower_bound(begin(), end(), k, me);
+ }
+
+ iterator upper_bound(const key_type& k)
+ {
+ MyCompare& me = *this;
+ return std::upper_bound(begin(), end(), k, me);
+ }
+
+ const_iterator upper_bound(const key_type& k) const
+ {
+ const MyCompare& me = *this;
+ return std::upper_bound(begin(), end(), k, me);
+ }
+
+ std::pair<iterator, iterator> equal_range(const key_type& k)
+ {
+ MyCompare& me = *this;
+ return std::equal_range(begin(), end(), k, me);
+ }
+
+ std::pair<const_iterator, const_iterator> equal_range(
+ const key_type& k) const
+ {
+ const MyCompare& me = *this;
+ return std::equal_range(begin(), end(), k, me);
+ }
+
+ template <class K1, class V1, class C1, class A1>
+ friend bool operator==(const AssocVector<K1, V1, C1, A1>& lhs,
+ const AssocVector<K1, V1, C1, A1>& rhs);
+
+ bool operator<(const AssocVector& rhs) const
+ {
+ const Base& me = *this;
+ const Base& yo = rhs;
+ return me < yo;
+ }
+
+ template <class K1, class V1, class C1, class A1>
+ friend bool operator!=(const AssocVector<K1, V1, C1, A1>& lhs,
+ const AssocVector<K1, V1, C1, A1>& rhs);
+
+ template <class K1, class V1, class C1, class A1>
+ friend bool operator>(const AssocVector<K1, V1, C1, A1>& lhs,
+ const AssocVector<K1, V1, C1, A1>& rhs);
+
+ template <class K1, class V1, class C1, class A1>
+ friend bool operator>=(const AssocVector<K1, V1, C1, A1>& lhs,
+ const AssocVector<K1, V1, C1, A1>& rhs);
+
+ template <class K1, class V1, class C1, class A1>
+ friend bool operator<=(const AssocVector<K1, V1, C1, A1>& lhs,
+ const AssocVector<K1, V1, C1, A1>& rhs);
+ };
+
+ template <class K, class V, class C, class A>
+ inline bool operator==(const AssocVector<K, V, C, A>& lhs,
+ const AssocVector<K, V, C, A>& rhs)
+ {
+ const std::vector<std::pair<K, V>, A>& me = lhs;
+ return me == rhs;
+ }
+
+ template <class K, class V, class C, class A>
+ inline bool operator!=(const AssocVector<K, V, C, A>& lhs,
+ const AssocVector<K, V, C, A>& rhs)
+ { return !(lhs == rhs); }
+
+ template <class K, class V, class C, class A>
+ inline bool operator>(const AssocVector<K, V, C, A>& lhs,
+ const AssocVector<K, V, C, A>& rhs)
+ { return rhs < lhs; }
+
+ template <class K, class V, class C, class A>
+ inline bool operator>=(const AssocVector<K, V, C, A>& lhs,
+ const AssocVector<K, V, C, A>& rhs)
+ { return !(lhs < rhs); }
+
+ template <class K, class V, class C, class A>
+ inline bool operator<=(const AssocVector<K, V, C, A>& lhs,
+ const AssocVector<K, V, C, A>& rhs)
+ { return !(rhs < lhs); }
+
+
+ // specialized algorithms:
+ template <class K, class V, class C, class A>
+ void swap(AssocVector<K, V, C, A>& lhs, AssocVector<K, V, C, A>& rhs)
+ { lhs.swap(rhs); }
+
+} // namespace Loki
diff --git a/contrib/python/kiwisolver/py2/kiwi/constraint.h b/contrib/python/kiwisolver/py2/kiwi/constraint.h
new file mode 100644
index 00000000000..558dd924aeb
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/constraint.h
@@ -0,0 +1,124 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <map>
+#include <vector>
+#include "expression.h"
+#include "shareddata.h"
+#include "strength.h"
+#include "term.h"
+#include "variable.h"
+
+
+namespace kiwi
+{
+
+enum RelationalOperator { OP_LE, OP_GE, OP_EQ };
+
+
+class Constraint
+{
+
+public:
+
+ Constraint() : m_data( 0 ) {}
+
+ Constraint( const Expression& expr,
+ RelationalOperator op,
+ double strength = strength::required ) :
+ m_data( new ConstraintData( expr, op, strength ) ) {}
+
+ Constraint( const Constraint& other, double strength ) :
+ m_data( new ConstraintData( other, strength ) ) {}
+
+ ~Constraint() {}
+
+ const Expression& expression() const
+ {
+ return m_data->m_expression;
+ }
+
+ RelationalOperator op() const
+ {
+ return m_data->m_op;
+ }
+
+ double strength() const
+ {
+ return m_data->m_strength;
+ }
+
+ bool operator!() const
+ {
+ return !m_data;
+ }
+
+private:
+
+ static Expression reduce( const Expression& expr )
+ {
+ std::map<Variable, double> vars;
+ typedef std::vector<Term>::const_iterator iter_t;
+ iter_t end = expr.terms().end();
+ for( iter_t it = expr.terms().begin(); it != end; ++it )
+ vars[ it->variable() ] += it->coefficient();
+ std::vector<Term> terms( vars.begin(), vars.end() );
+ return Expression( terms, expr.constant() );
+ }
+
+ class ConstraintData : public SharedData
+ {
+
+ public:
+
+ ConstraintData( const Expression& expr,
+ RelationalOperator op,
+ double strength ) :
+ SharedData(),
+ m_expression( reduce( expr ) ),
+ m_strength( strength::clip( strength ) ),
+ m_op( op ) {}
+
+ ConstraintData( const Constraint& other, double strength ) :
+ SharedData(),
+ m_expression( other.expression() ),
+ m_strength( strength::clip( strength ) ),
+ m_op( other.op() ) {}
+
+ ~ConstraintData() {}
+
+ Expression m_expression;
+ double m_strength;
+ RelationalOperator m_op;
+
+ private:
+
+ ConstraintData( const ConstraintData& other );
+
+ ConstraintData& operator=( const ConstraintData& other );
+ };
+
+ SharedDataPtr<ConstraintData> m_data;
+
+ friend bool operator<( const Constraint& lhs, const Constraint& rhs )
+ {
+ return lhs.m_data < rhs.m_data;
+ }
+
+ friend bool operator==( const Constraint& lhs, const Constraint& rhs )
+ {
+ return lhs.m_data == rhs.m_data;
+ }
+
+ friend bool operator!=( const Constraint& lhs, const Constraint& rhs )
+ {
+ return lhs.m_data != rhs.m_data;
+ }
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/debug.h b/contrib/python/kiwisolver/py2/kiwi/debug.h
new file mode 100644
index 00000000000..007a24da5ed
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/debug.h
@@ -0,0 +1,203 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include "constraint.h"
+#include "solverimpl.h"
+#include "term.h"
+
+
+namespace kiwi
+{
+
+namespace impl
+{
+
+class DebugHelper
+{
+
+public:
+
+ static void dump( const SolverImpl& solver, std::ostream& out )
+ {
+ out << "Objective" << std::endl;
+ out << "---------" << std::endl;
+ dump( *solver.m_objective, out );
+ out << std::endl;
+ out << "Tableau" << std::endl;
+ out << "-------" << std::endl;
+ dump( solver.m_rows, out );
+ out << std::endl;
+ out << "Infeasible" << std::endl;
+ out << "----------" << std::endl;
+ dump( solver.m_infeasible_rows, out );
+ out << std::endl;
+ out << "Variables" << std::endl;
+ out << "---------" << std::endl;
+ dump( solver.m_vars, out );
+ out << std::endl;
+ out << "Edit Variables" << std::endl;
+ out << "--------------" << std::endl;
+ dump( solver.m_edits, out );
+ out << std::endl;
+ out << "Constraints" << std::endl;
+ out << "-----------" << std::endl;
+ dump( solver.m_cns, out );
+ out << std::endl;
+ out << std::endl;
+ }
+
+ static void dump( const SolverImpl::RowMap& rows, std::ostream& out )
+ {
+ typedef SolverImpl::RowMap::const_iterator iter_t;
+ iter_t end = rows.end();
+ for( iter_t it = rows.begin(); it != end; ++it )
+ {
+ dump( it->first, out );
+ out << " | ";
+ dump( *it->second, out );
+ }
+ }
+
+ static void dump( const std::vector<Symbol>& symbols, std::ostream& out )
+ {
+ typedef std::vector<Symbol>::const_iterator iter_t;
+ iter_t end = symbols.end();
+ for( iter_t it = symbols.begin(); it != end; ++it )
+ {
+ dump( *it, out );
+ out << std::endl;
+ }
+ }
+
+ static void dump( const SolverImpl::VarMap& vars, std::ostream& out )
+ {
+ typedef SolverImpl::VarMap::const_iterator iter_t;
+ iter_t end = vars.end();
+ for( iter_t it = vars.begin(); it != end; ++it )
+ {
+ out << it->first.name() << " = ";
+ dump( it->second, out );
+ out << std::endl;
+ }
+ }
+
+ static void dump( const SolverImpl::CnMap& cns, std::ostream& out )
+ {
+ typedef SolverImpl::CnMap::const_iterator iter_t;
+ iter_t end = cns.end();
+ for( iter_t it = cns.begin(); it != end; ++it )
+ dump( it->first, out );
+ }
+
+ static void dump( const SolverImpl::EditMap& edits, std::ostream& out )
+ {
+ typedef SolverImpl::EditMap::const_iterator iter_t;
+ iter_t end = edits.end();
+ for( iter_t it = edits.begin(); it != end; ++it )
+ out << it->first.name() << std::endl;
+ }
+
+ static void dump( const Row& row, std::ostream& out )
+ {
+ typedef Row::CellMap::const_iterator iter_t;
+ out << row.constant();
+ iter_t end = row.cells().end();
+ for( iter_t it = row.cells().begin(); it != end; ++it )
+ {
+ out << " + " << it->second << " * ";
+ dump( it->first, out );
+ }
+ out << std::endl;
+ }
+
+ static void dump( const Symbol& symbol, std::ostream& out )
+ {
+ switch( symbol.type() )
+ {
+ case Symbol::Invalid:
+ out << "i";
+ break;
+ case Symbol::External:
+ out << "v";
+ break;
+ case Symbol::Slack:
+ out << "s";
+ break;
+ case Symbol::Error:
+ out << "e";
+ break;
+ case Symbol::Dummy:
+ out << "d";
+ break;
+ default:
+ break;
+ }
+ out << symbol.id();
+ }
+
+ static void dump( const Constraint& cn, std::ostream& out )
+ {
+ typedef std::vector<Term>::const_iterator iter_t;
+ iter_t begin = cn.expression().terms().begin();
+ iter_t end = cn.expression().terms().end();
+ for( iter_t it = begin; it != end; ++it )
+ {
+ out << it->coefficient() << " * ";
+ out << it->variable().name() << " + ";
+ }
+ out << cn.expression().constant();
+ switch( cn.op() )
+ {
+ case OP_LE:
+ out << " <= 0 ";
+ break;
+ case OP_GE:
+ out << " >= 0 ";
+ break;
+ case OP_EQ:
+ out << " == 0 ";
+ break;
+ default:
+ break;
+ }
+ out << " | strength = " << cn.strength() << std::endl;
+ }
+};
+
+} // namespace impl
+
+
+namespace debug
+{
+
+template<typename T>
+void dump( const T& value )
+{
+ impl::DebugHelper::dump( value, std::cout );
+}
+
+template<typename T>
+void dump( const T& value, std::ostream& out )
+{
+ impl::DebugHelper::dump( value, out );
+}
+
+template<typename T>
+std::string dumps( const T& value )
+{
+ std::stringstream stream;
+ impl::DebugHelper::dump( value, stream );
+ return stream.str();
+}
+
+} // namespace debug
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/errors.h b/contrib/python/kiwisolver/py2/kiwi/errors.h
new file mode 100644
index 00000000000..6c77eee0b70
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/errors.h
@@ -0,0 +1,188 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <exception>
+#include <string>
+#include "constraint.h"
+#include "variable.h"
+
+
+namespace kiwi
+{
+
+
+class UnsatisfiableConstraint : public std::exception
+{
+
+public:
+
+ UnsatisfiableConstraint( const Constraint& constraint ) :
+ m_constraint( constraint ) {}
+
+ ~UnsatisfiableConstraint() throw() {}
+
+ const char* what() const throw()
+ {
+ return "The constraint can not be satisfied.";
+ }
+
+ const Constraint& constraint() const
+ {
+ return m_constraint;
+ }
+
+private:
+
+ Constraint m_constraint;
+};
+
+
+class UnknownConstraint : public std::exception
+{
+
+public:
+
+ UnknownConstraint( const Constraint& constraint ) :
+ m_constraint( constraint ) {}
+
+ ~UnknownConstraint() throw() {}
+
+ const char* what() const throw()
+ {
+ return "The constraint has not been added to the solver.";
+ }
+
+ const Constraint& constraint() const
+ {
+ return m_constraint;
+ }
+
+private:
+
+ Constraint m_constraint;
+};
+
+
+class DuplicateConstraint : public std::exception
+{
+
+public:
+
+ DuplicateConstraint( const Constraint& constraint ) :
+ m_constraint( constraint ) {}
+
+ ~DuplicateConstraint() throw() {}
+
+ const char* what() const throw()
+ {
+ return "The constraint has already been added to the solver.";
+ }
+
+ const Constraint& constraint() const
+ {
+ return m_constraint;
+ }
+
+private:
+
+ Constraint m_constraint;
+};
+
+
+class UnknownEditVariable : public std::exception
+{
+
+public:
+
+ UnknownEditVariable( const Variable& variable ) :
+ m_variable( variable ) {}
+
+ ~UnknownEditVariable() throw() {}
+
+ const char* what() const throw()
+ {
+ return "The edit variable has not been added to the solver.";
+ }
+
+ const Variable& variable() const
+ {
+ return m_variable;
+ }
+
+private:
+
+ Variable m_variable;
+};
+
+
+class DuplicateEditVariable : public std::exception
+{
+
+public:
+
+ DuplicateEditVariable( const Variable& variable ) :
+ m_variable( variable ) {}
+
+ ~DuplicateEditVariable() throw() {}
+
+ const char* what() const throw()
+ {
+ return "The edit variable has already been added to the solver.";
+ }
+
+ const Variable& variable() const
+ {
+ return m_variable;
+ }
+
+private:
+
+ Variable m_variable;
+};
+
+
+class BadRequiredStrength : public std::exception
+{
+
+public:
+
+ BadRequiredStrength() {}
+
+ ~BadRequiredStrength() throw() {}
+
+ const char* what() const throw()
+ {
+ return "A required strength cannot be used in this context.";
+ }
+};
+
+
+class InternalSolverError : public std::exception
+{
+
+public:
+
+ InternalSolverError() : m_msg( "An internal solver error ocurred." ) {}
+
+ InternalSolverError( const char* msg ) : m_msg( msg ) {}
+
+ InternalSolverError( const std::string& msg ) : m_msg( msg ) {}
+
+ ~InternalSolverError() throw() {}
+
+ const char* what() const throw()
+ {
+ return m_msg.c_str();
+ }
+
+private:
+
+ std::string m_msg;
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/expression.h b/contrib/python/kiwisolver/py2/kiwi/expression.h
new file mode 100644
index 00000000000..6d757206bd7
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/expression.h
@@ -0,0 +1,57 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <vector>
+#include "term.h"
+
+
+namespace kiwi
+{
+
+class Expression
+{
+
+public:
+
+ Expression( double constant = 0.0 ) : m_constant( constant ) {}
+
+ Expression( const Term& term, double constant = 0.0 ) :
+ m_terms( 1, term ), m_constant( constant ) {}
+
+ Expression( const std::vector<Term>& terms, double constant = 0.0 ) :
+ m_terms( terms ), m_constant( constant ) {}
+
+ ~Expression() {}
+
+ const std::vector<Term>& terms() const
+ {
+ return m_terms;
+ }
+
+ double constant() const
+ {
+ return m_constant;
+ }
+
+ double value() const
+ {
+ typedef std::vector<Term>::const_iterator iter_t;
+ double result = m_constant;
+ iter_t end = m_terms.end();
+ for( iter_t it = m_terms.begin(); it != end; ++it )
+ result += it->value();
+ return result;
+ }
+
+private:
+
+ std::vector<Term> m_terms;
+ double m_constant;
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/kiwi.h b/contrib/python/kiwisolver/py2/kiwi/kiwi.h
new file mode 100644
index 00000000000..e5e3d85c90b
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/kiwi.h
@@ -0,0 +1,19 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include "constraint.h"
+#include "debug.h"
+#include "errors.h"
+#include "expression.h"
+#include "shareddata.h"
+#include "solver.h"
+#include "strength.h"
+#include "symbolics.h"
+#include "term.h"
+#include "variable.h"
+#include "version.h"
diff --git a/contrib/python/kiwisolver/py2/kiwi/maptype.h b/contrib/python/kiwisolver/py2/kiwi/maptype.h
new file mode 100644
index 00000000000..d125b07cc2d
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/maptype.h
@@ -0,0 +1,38 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <functional>
+#include <map>
+#include <memory>
+#include <utility>
+#include "AssocVector.h"
+
+
+namespace kiwi
+{
+
+namespace impl
+{
+
+template<
+ typename K,
+ typename V,
+ typename C = std::less<K>,
+ typename A = std::allocator< std::pair<K, V> > >
+class MapType
+{
+public:
+ typedef Loki::AssocVector<K, V, C, A> Type;
+ //typedef std::map<K, V, C, A> Type;
+private:
+ MapType();
+};
+
+} // namespace impl
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/row.h b/contrib/python/kiwisolver/py2/kiwi/row.h
new file mode 100644
index 00000000000..33b501df76c
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/row.h
@@ -0,0 +1,192 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include "maptype.h"
+#include "symbol.h"
+#include "util.h"
+
+
+namespace kiwi
+{
+
+namespace impl
+{
+
+class Row
+{
+
+public:
+
+ typedef MapType<Symbol, double>::Type CellMap;
+
+ Row() : m_constant( 0.0 ) {}
+
+ Row( double constant ) : m_constant( constant ) {}
+
+ Row( const Row& other ) :
+ m_cells( other.m_cells ), m_constant( other.m_constant ) {}
+
+ ~Row() {}
+
+ const CellMap& cells() const
+ {
+ return m_cells;
+ }
+
+ double constant() const
+ {
+ return m_constant;
+ }
+
+ /* Add a constant value to the row constant.
+
+ The new value of the constant is returned.
+
+ */
+ double add( double value )
+ {
+ return m_constant += value;
+ }
+
+ /* Insert a symbol into the row with a given coefficient.
+
+ If the symbol already exists in the row, the coefficient will be
+ added to the existing coefficient. If the resulting coefficient
+ is zero, the symbol will be removed from the row.
+
+ */
+ void insert( const Symbol& symbol, double coefficient = 1.0 )
+ {
+ if( nearZero( m_cells[ symbol ] += coefficient ) )
+ m_cells.erase( symbol );
+ }
+
+ /* Insert a row into this row with a given coefficient.
+
+ The constant and the cells of the other row will be multiplied by
+ the coefficient and added to this row. Any cell with a resulting
+ coefficient of zero will be removed from the row.
+
+ */
+ void insert( const Row& other, double coefficient = 1.0 )
+ {
+ typedef CellMap::const_iterator iter_t;
+ m_constant += other.m_constant * coefficient;
+ iter_t end = other.m_cells.end();
+ for( iter_t it = other.m_cells.begin(); it != end; ++it )
+ {
+ double coeff = it->second * coefficient;
+ if( nearZero( m_cells[ it->first ] += coeff ) )
+ m_cells.erase( it->first );
+ }
+ }
+
+ /* Remove the given symbol from the row.
+
+ */
+ void remove( const Symbol& symbol )
+ {
+ CellMap::iterator it = m_cells.find( symbol );
+ if( it != m_cells.end() )
+ m_cells.erase( it );
+ }
+
+ /* Reverse the sign of the constant and all cells in the row.
+
+ */
+ void reverseSign()
+ {
+ typedef CellMap::iterator iter_t;
+ m_constant = -m_constant;
+ iter_t end = m_cells.end();
+ for( iter_t it = m_cells.begin(); it != end; ++it )
+ it->second = -it->second;
+ }
+
+ /* Solve the row for the given symbol.
+
+ This method assumes the row is of the form a * x + b * y + c = 0
+ and (assuming solve for x) will modify the row to represent the
+ right hand side of x = -b/a * y - c / a. The target symbol will
+ be removed from the row, and the constant and other cells will
+ be multiplied by the negative inverse of the target coefficient.
+
+ The given symbol *must* exist in the row.
+
+ */
+ void solveFor( const Symbol& symbol )
+ {
+ typedef CellMap::iterator iter_t;
+ double coeff = -1.0 / m_cells[ symbol ];
+ m_cells.erase( symbol );
+ m_constant *= coeff;
+ iter_t end = m_cells.end();
+ for( iter_t it = m_cells.begin(); it != end; ++it )
+ it->second *= coeff;
+ }
+
+ /* Solve the row for the given symbols.
+
+ This method assumes the row is of the form x = b * y + c and will
+ solve the row such that y = x / b - c / b. The rhs symbol will be
+ removed from the row, the lhs added, and the result divided by the
+ negative inverse of the rhs coefficient.
+
+ The lhs symbol *must not* exist in the row, and the rhs symbol
+ *must* exist in the row.
+
+ */
+ void solveFor( const Symbol& lhs, const Symbol& rhs )
+ {
+ insert( lhs, -1.0 );
+ solveFor( rhs );
+ }
+
+ /* Get the coefficient for the given symbol.
+
+ If the symbol does not exist in the row, zero will be returned.
+
+ */
+ double coefficientFor( const Symbol& symbol ) const
+ {
+ CellMap::const_iterator it = m_cells.find( symbol );
+ if( it == m_cells.end() )
+ return 0.0;
+ return it->second;
+ }
+
+ /* Substitute a symbol with the data from another row.
+
+ Given a row of the form a * x + b and a substitution of the
+ form x = 3 * y + c the row will be updated to reflect the
+ expression 3 * a * y + a * c + b.
+
+ If the symbol does not exist in the row, this is a no-op.
+
+ */
+ void substitute( const Symbol& symbol, const Row& row )
+ {
+ typedef CellMap::iterator iter_t;
+ iter_t it = m_cells.find( symbol );
+ if( it != m_cells.end() )
+ {
+ double coefficient = it->second;
+ m_cells.erase( it );
+ insert( row, coefficient );
+ }
+ }
+
+private:
+
+ CellMap m_cells;
+ double m_constant;
+};
+
+} // namespace impl
+
+} // namespace
diff --git a/contrib/python/kiwisolver/py2/kiwi/shareddata.h b/contrib/python/kiwisolver/py2/kiwi/shareddata.h
new file mode 100644
index 00000000000..b7d389ee6dc
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/shareddata.h
@@ -0,0 +1,157 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+
+
+namespace kiwi
+{
+
+class SharedData
+{
+
+public:
+
+ SharedData() : m_refcount( 0 ) {}
+
+ SharedData( const SharedData& other ) : m_refcount( 0 ) {}
+
+ int m_refcount;
+
+private:
+
+ SharedData& operator=( const SharedData& other );
+};
+
+
+template<typename T>
+class SharedDataPtr
+{
+
+public:
+
+ typedef T Type;
+
+ SharedDataPtr() : m_data( 0 ) {}
+
+ explicit SharedDataPtr( T* data ) : m_data( data )
+ {
+ incref( m_data );
+ }
+
+ ~SharedDataPtr()
+ {
+ decref( m_data );
+ }
+
+ T* data()
+ {
+ return m_data;
+ }
+
+ const T* data() const
+ {
+ return m_data;
+ }
+
+ operator T*()
+ {
+ return m_data;
+ }
+
+ operator const T*() const
+ {
+ return m_data;
+ }
+
+ T* operator->()
+ {
+ return m_data;
+ }
+
+ const T* operator->() const
+ {
+ return m_data;
+ }
+
+ T& operator*()
+ {
+ return *m_data;
+ }
+
+ const T& operator*() const
+ {
+ return *m_data;
+ }
+
+ bool operator!() const
+ {
+ return !m_data;
+ }
+
+ bool operator<( const SharedDataPtr<T>& other ) const
+ {
+ return m_data < other.m_data;
+ }
+
+ bool operator==( const SharedDataPtr<T>& other ) const
+ {
+ return m_data == other.m_data;
+ }
+
+ bool operator!=( const SharedDataPtr<T>& other ) const
+ {
+ return m_data != other.m_data;
+ }
+
+ SharedDataPtr( const SharedDataPtr<T>& other ) : m_data( other.m_data )
+ {
+ incref( m_data );
+ }
+
+ SharedDataPtr<T>& operator=( const SharedDataPtr<T>& other )
+ {
+ if( m_data != other.m_data )
+ {
+ T* temp = m_data;
+ m_data = other.m_data;
+ incref( m_data );
+ decref( temp );
+ }
+ return *this;
+ }
+
+ SharedDataPtr<T>& operator=( T* other )
+ {
+ if( m_data != other )
+ {
+ T* temp = m_data;
+ m_data = other;
+ incref( m_data );
+ decref( temp );
+ }
+ return *this;
+ }
+
+private:
+
+ static void incref( T* data )
+ {
+ if( data )
+ ++data->m_refcount;
+ }
+
+ static void decref( T* data )
+ {
+ if( data && --data->m_refcount == 0 )
+ delete data;
+ }
+
+ T* m_data;
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/solver.h b/contrib/python/kiwisolver/py2/kiwi/solver.h
new file mode 100644
index 00000000000..8eed1841bf9
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/solver.h
@@ -0,0 +1,178 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include "constraint.h"
+#include "debug.h"
+#include "solverimpl.h"
+#include "strength.h"
+#include "variable.h"
+
+
+namespace kiwi
+{
+
+class Solver
+{
+
+public:
+
+ Solver() {}
+
+ ~Solver() {}
+
+ /* Add a constraint to the solver.
+
+ Throws
+ ------
+ DuplicateConstraint
+ The given constraint has already been added to the solver.
+
+ UnsatisfiableConstraint
+ The given constraint is required and cannot be satisfied.
+
+ */
+ void addConstraint( const Constraint& constraint )
+ {
+ m_impl.addConstraint( constraint );
+ }
+
+ /* Remove a constraint from the solver.
+
+ Throws
+ ------
+ UnknownConstraint
+ The given constraint has not been added to the solver.
+
+ */
+ void removeConstraint( const Constraint& constraint )
+ {
+ m_impl.removeConstraint( constraint );
+ }
+
+ /* Test whether a constraint has been added to the solver.
+
+ */
+ bool hasConstraint( const Constraint& constraint ) const
+ {
+ return m_impl.hasConstraint( constraint );
+ }
+
+ /* Add an edit variable to the solver.
+
+ This method should be called before the `suggestValue` method is
+ used to supply a suggested value for the given edit variable.
+
+ Throws
+ ------
+ DuplicateEditVariable
+ The given edit variable has already been added to the solver.
+
+ BadRequiredStrength
+ The given strength is >= required.
+
+ */
+ void addEditVariable( const Variable& variable, double strength )
+ {
+ m_impl.addEditVariable( variable, strength );
+ }
+
+ /* Remove an edit variable from the solver.
+
+ Throws
+ ------
+ UnknownEditVariable
+ The given edit variable has not been added to the solver.
+
+ */
+ void removeEditVariable( const Variable& variable )
+ {
+ m_impl.removeEditVariable( variable );
+ }
+
+ /* Test whether an edit variable has been added to the solver.
+
+ */
+ bool hasEditVariable( const Variable& variable ) const
+ {
+ return m_impl.hasEditVariable( variable );
+ }
+
+ /* Suggest a value for the given edit variable.
+
+ This method should be used after an edit variable as been added to
+ the solver in order to suggest the value for that variable. After
+ all suggestions have been made, the `solve` method can be used to
+ update the values of all variables.
+
+ Throws
+ ------
+ UnknownEditVariable
+ The given edit variable has not been added to the solver.
+
+ */
+ void suggestValue( const Variable& variable, double value )
+ {
+ m_impl.suggestValue( variable, value );
+ }
+
+ /* Update the values of the external solver variables.
+
+ */
+ void updateVariables()
+ {
+ m_impl.updateVariables();
+ }
+
+ /* Reset the solver to the empty starting condition.
+
+ This method resets the internal solver state to the empty starting
+ condition, as if no constraints or edit variables have been added.
+ This can be faster than deleting the solver and creating a new one
+ when the entire system must change, since it can avoid unecessary
+ heap (de)allocations.
+
+ */
+ void reset()
+ {
+ m_impl.reset();
+ }
+
+ /* Dump a representation of the solver internals to stdout.
+
+ */
+ void dump()
+ {
+ debug::dump( m_impl );
+ }
+
+ /* Dump a representation of the solver internals to a stream.
+
+ */
+ void dump( std::ostream& out )
+ {
+ debug::dump( m_impl, out );
+ }
+
+ /* Dump a representation of the solver internals to a string.
+
+ */
+ std::string dumps()
+ {
+ return debug::dumps( m_impl );
+ }
+
+private:
+
+ Solver( const Solver& );
+
+ Solver& operator=( const Solver& );
+
+ impl::SolverImpl m_impl;
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/solverimpl.h b/contrib/python/kiwisolver/py2/kiwi/solverimpl.h
new file mode 100644
index 00000000000..9b56ee28188
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/solverimpl.h
@@ -0,0 +1,840 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <vector>
+#include "constraint.h"
+#include "errors.h"
+#include "expression.h"
+#include "maptype.h"
+#include "row.h"
+#include "symbol.h"
+#include "term.h"
+#include "util.h"
+#include "variable.h"
+
+
+namespace kiwi
+{
+
+namespace impl
+{
+
+class SolverImpl
+{
+ friend class DebugHelper;
+
+ struct Tag
+ {
+ Symbol marker;
+ Symbol other;
+ };
+
+ struct EditInfo
+ {
+ Tag tag;
+ Constraint constraint;
+ double constant;
+ };
+
+ typedef MapType<Variable, Symbol>::Type VarMap;
+
+ typedef MapType<Symbol, Row*>::Type RowMap;
+
+ typedef MapType<Constraint, Tag>::Type CnMap;
+
+ typedef MapType<Variable, EditInfo>::Type EditMap;
+
+ struct DualOptimizeGuard
+ {
+ DualOptimizeGuard( SolverImpl& impl ) : m_impl( impl ) {}
+ ~DualOptimizeGuard() { m_impl.dualOptimize(); }
+ SolverImpl& m_impl;
+ };
+
+public:
+
+ SolverImpl() : m_objective( new Row() ), m_id_tick( 1 ) {}
+
+ ~SolverImpl() { clearRows(); }
+
+ /* Add a constraint to the solver.
+
+ Throws
+ ------
+ DuplicateConstraint
+ The given constraint has already been added to the solver.
+
+ UnsatisfiableConstraint
+ The given constraint is required and cannot be satisfied.
+
+ */
+ void addConstraint( const Constraint& constraint )
+ {
+ if( m_cns.find( constraint ) != m_cns.end() )
+ throw DuplicateConstraint( constraint );
+
+ // Creating a row causes symbols to be reserved for the variables
+ // in the constraint. If this method exits with an exception,
+ // then its possible those variables will linger in the var map.
+ // Since its likely that those variables will be used in other
+ // constraints and since exceptional conditions are uncommon,
+ // i'm not too worried about aggressive cleanup of the var map.
+ Tag tag;
+ std::auto_ptr<Row> rowptr( createRow( constraint, tag ) );
+ Symbol subject( chooseSubject( *rowptr, tag ) );
+
+ // If chooseSubject could not find a valid entering symbol, one
+ // last option is available if the entire row is composed of
+ // dummy variables. If the constant of the row is zero, then
+ // this represents redundant constraints and the new dummy
+ // marker can enter the basis. If the constant is non-zero,
+ // then it represents an unsatisfiable constraint.
+ if( subject.type() == Symbol::Invalid && allDummies( *rowptr ) )
+ {
+ if( !nearZero( rowptr->constant() ) )
+ throw UnsatisfiableConstraint( constraint );
+ else
+ subject = tag.marker;
+ }
+
+ // If an entering symbol still isn't found, then the row must
+ // be added using an artificial variable. If that fails, then
+ // the row represents an unsatisfiable constraint.
+ if( subject.type() == Symbol::Invalid )
+ {
+ if( !addWithArtificialVariable( *rowptr ) )
+ throw UnsatisfiableConstraint( constraint );
+ }
+ else
+ {
+ rowptr->solveFor( subject );
+ substitute( subject, *rowptr );
+ m_rows[ subject ] = rowptr.release();
+ }
+
+ m_cns[ constraint ] = tag;
+
+ // Optimizing after each constraint is added performs less
+ // aggregate work due to a smaller average system size. It
+ // also ensures the solver remains in a consistent state.
+ optimize( *m_objective );
+ }
+
+ /* Remove a constraint from the solver.
+
+ Throws
+ ------
+ UnknownConstraint
+ The given constraint has not been added to the solver.
+
+ */
+ void removeConstraint( const Constraint& constraint )
+ {
+ CnMap::iterator cn_it = m_cns.find( constraint );
+ if( cn_it == m_cns.end() )
+ throw UnknownConstraint( constraint );
+
+ Tag tag( cn_it->second );
+ m_cns.erase( cn_it );
+
+ // Remove the error effects from the objective function
+ // *before* pivoting, or substitutions into the objective
+ // will lead to incorrect solver results.
+ removeConstraintEffects( constraint, tag );
+
+ // If the marker is basic, simply drop the row. Otherwise,
+ // pivot the marker into the basis and then drop the row.
+ RowMap::iterator row_it = m_rows.find( tag.marker );
+ if( row_it != m_rows.end() )
+ {
+ std::auto_ptr<Row> rowptr( row_it->second );
+ m_rows.erase( row_it );
+ }
+ else
+ {
+ row_it = getMarkerLeavingRow( tag.marker );
+ if( row_it == m_rows.end() )
+ throw InternalSolverError( "failed to find leaving row" );
+ Symbol leaving( row_it->first );
+ std::auto_ptr<Row> rowptr( row_it->second );
+ m_rows.erase( row_it );
+ rowptr->solveFor( leaving, tag.marker );
+ substitute( tag.marker, *rowptr );
+ }
+
+ // Optimizing after each constraint is removed ensures that the
+ // solver remains consistent. It makes the solver api easier to
+ // use at a small tradeoff for speed.
+ optimize( *m_objective );
+ }
+
+ /* Test whether a constraint has been added to the solver.
+
+ */
+ bool hasConstraint( const Constraint& constraint ) const
+ {
+ return m_cns.find( constraint ) != m_cns.end();
+ }
+
+ /* Add an edit variable to the solver.
+
+ This method should be called before the `suggestValue` method is
+ used to supply a suggested value for the given edit variable.
+
+ Throws
+ ------
+ DuplicateEditVariable
+ The given edit variable has already been added to the solver.
+
+ BadRequiredStrength
+ The given strength is >= required.
+
+ */
+ void addEditVariable( const Variable& variable, double strength )
+ {
+ if( m_edits.find( variable ) != m_edits.end() )
+ throw DuplicateEditVariable( variable );
+ strength = strength::clip( strength );
+ if( strength == strength::required )
+ throw BadRequiredStrength();
+ Constraint cn( Expression( variable ), OP_EQ, strength );
+ addConstraint( cn );
+ EditInfo info;
+ info.tag = m_cns[ cn ];
+ info.constraint = cn;
+ info.constant = 0.0;
+ m_edits[ variable ] = info;
+ }
+
+ /* Remove an edit variable from the solver.
+
+ Throws
+ ------
+ UnknownEditVariable
+ The given edit variable has not been added to the solver.
+
+ */
+ void removeEditVariable( const Variable& variable )
+ {
+ EditMap::iterator it = m_edits.find( variable );
+ if( it == m_edits.end() )
+ throw UnknownEditVariable( variable );
+ removeConstraint( it->second.constraint );
+ m_edits.erase( it );
+ }
+
+ /* Test whether an edit variable has been added to the solver.
+
+ */
+ bool hasEditVariable( const Variable& variable ) const
+ {
+ return m_edits.find( variable ) != m_edits.end();
+ }
+
+ /* Suggest a value for the given edit variable.
+
+ This method should be used after an edit variable as been added to
+ the solver in order to suggest the value for that variable.
+
+ Throws
+ ------
+ UnknownEditVariable
+ The given edit variable has not been added to the solver.
+
+ */
+ void suggestValue( const Variable& variable, double value )
+ {
+ EditMap::iterator it = m_edits.find( variable );
+ if( it == m_edits.end() )
+ throw UnknownEditVariable( variable );
+
+ DualOptimizeGuard guard( *this );
+ EditInfo& info = it->second;
+ double delta = value - info.constant;
+ info.constant = value;
+
+ // Check first if the positive error variable is basic.
+ RowMap::iterator row_it = m_rows.find( info.tag.marker );
+ if( row_it != m_rows.end() )
+ {
+ if( row_it->second->add( -delta ) < 0.0 )
+ m_infeasible_rows.push_back( row_it->first );
+ return;
+ }
+
+ // Check next if the negative error variable is basic.
+ row_it = m_rows.find( info.tag.other );
+ if( row_it != m_rows.end() )
+ {
+ if( row_it->second->add( delta ) < 0.0 )
+ m_infeasible_rows.push_back( row_it->first );
+ return;
+ }
+
+ // Otherwise update each row where the error variables exist.
+ RowMap::iterator end = m_rows.end();
+ for( row_it = m_rows.begin(); row_it != end; ++row_it )
+ {
+ double coeff = row_it->second->coefficientFor( info.tag.marker );
+ if( coeff != 0.0 &&
+ row_it->second->add( delta * coeff ) < 0.0 &&
+ row_it->first.type() != Symbol::External )
+ m_infeasible_rows.push_back( row_it->first );
+ }
+ }
+
+ /* Update the values of the external solver variables.
+
+ */
+ void updateVariables()
+ {
+ typedef RowMap::iterator row_iter_t;
+ typedef VarMap::iterator var_iter_t;
+ row_iter_t row_end = m_rows.end();
+ var_iter_t var_end = m_vars.end();
+ for( var_iter_t var_it = m_vars.begin(); var_it != var_end; ++var_it )
+ {
+ Variable& var( const_cast<Variable&>( var_it->first ) );
+ row_iter_t row_it = m_rows.find( var_it->second );
+ if( row_it == row_end )
+ var.setValue( 0.0 );
+ else
+ var.setValue( row_it->second->constant() );
+ }
+ }
+
+ /* Reset the solver to the empty starting condition.
+
+ This method resets the internal solver state to the empty starting
+ condition, as if no constraints or edit variables have been added.
+ This can be faster than deleting the solver and creating a new one
+ when the entire system must change, since it can avoid unecessary
+ heap (de)allocations.
+
+ */
+ void reset()
+ {
+ clearRows();
+ m_cns.clear();
+ m_vars.clear();
+ m_edits.clear();
+ m_infeasible_rows.clear();
+ m_objective.reset( new Row() );
+ m_artificial.reset();
+ m_id_tick = 1;
+ }
+
+private:
+
+ SolverImpl( const SolverImpl& );
+
+ SolverImpl& operator=( const SolverImpl& );
+
+ struct RowDeleter
+ {
+ template<typename T>
+ void operator()( T& pair ) { delete pair.second; }
+ };
+
+ void clearRows()
+ {
+ std::for_each( m_rows.begin(), m_rows.end(), RowDeleter() );
+ m_rows.clear();
+ }
+
+ /* Get the symbol for the given variable.
+
+ If a symbol does not exist for the variable, one will be created.
+
+ */
+ Symbol getVarSymbol( const Variable& variable )
+ {
+ VarMap::iterator it = m_vars.find( variable );
+ if( it != m_vars.end() )
+ return it->second;
+ Symbol symbol( Symbol::External, m_id_tick++ );
+ m_vars[ variable ] = symbol;
+ return symbol;
+ }
+
+ /* Create a new Row object for the given constraint.
+
+ The terms in the constraint will be converted to cells in the row.
+ Any term in the constraint with a coefficient of zero is ignored.
+ This method uses the `getVarSymbol` method to get the symbol for
+ the variables added to the row. If the symbol for a given cell
+ variable is basic, the cell variable will be substituted with the
+ basic row.
+
+ The necessary slack and error variables will be added to the row.
+ If the constant for the row is negative, the sign for the row
+ will be inverted so the constant becomes positive.
+
+ The tag will be updated with the marker and error symbols to use
+ for tracking the movement of the constraint in the tableau.
+
+ */
+ Row* createRow( const Constraint& constraint, Tag& tag )
+ {
+ typedef std::vector<Term>::const_iterator iter_t;
+ const Expression& expr( constraint.expression() );
+ Row* row = new Row( expr.constant() );
+
+ // Substitute the current basic variables into the row.
+ iter_t end = expr.terms().end();
+ for( iter_t it = expr.terms().begin(); it != end; ++it )
+ {
+ if( !nearZero( it->coefficient() ) )
+ {
+ Symbol symbol( getVarSymbol( it->variable() ) );
+ RowMap::const_iterator row_it = m_rows.find( symbol );
+ if( row_it != m_rows.end() )
+ row->insert( *row_it->second, it->coefficient() );
+ else
+ row->insert( symbol, it->coefficient() );
+ }
+ }
+
+ // Add the necessary slack, error, and dummy variables.
+ switch( constraint.op() )
+ {
+ case OP_LE:
+ case OP_GE:
+ {
+ double coeff = constraint.op() == OP_LE ? 1.0 : -1.0;
+ Symbol slack( Symbol::Slack, m_id_tick++ );
+ tag.marker = slack;
+ row->insert( slack, coeff );
+ if( constraint.strength() < strength::required )
+ {
+ Symbol error( Symbol::Error, m_id_tick++ );
+ tag.other = error;
+ row->insert( error, -coeff );
+ m_objective->insert( error, constraint.strength() );
+ }
+ break;
+ }
+ case OP_EQ:
+ {
+ if( constraint.strength() < strength::required )
+ {
+ Symbol errplus( Symbol::Error, m_id_tick++ );
+ Symbol errminus( Symbol::Error, m_id_tick++ );
+ tag.marker = errplus;
+ tag.other = errminus;
+ row->insert( errplus, -1.0 ); // v = eplus - eminus
+ row->insert( errminus, 1.0 ); // v - eplus + eminus = 0
+ m_objective->insert( errplus, constraint.strength() );
+ m_objective->insert( errminus, constraint.strength() );
+ }
+ else
+ {
+ Symbol dummy( Symbol::Dummy, m_id_tick++ );
+ tag.marker = dummy;
+ row->insert( dummy );
+ }
+ break;
+ }
+ }
+
+ // Ensure the row as a positive constant.
+ if( row->constant() < 0.0 )
+ row->reverseSign();
+
+ return row;
+ }
+
+ /* Choose the subject for solving for the row.
+
+ This method will choose the best subject for using as the solve
+ target for the row. An invalid symbol will be returned if there
+ is no valid target.
+
+ The symbols are chosen according to the following precedence:
+
+ 1) The first symbol representing an external variable.
+ 2) A negative slack or error tag variable.
+
+ If a subject cannot be found, an invalid symbol will be returned.
+
+ */
+ Symbol chooseSubject( const Row& row, const Tag& tag )
+ {
+ typedef Row::CellMap::const_iterator iter_t;
+ iter_t end = row.cells().end();
+ for( iter_t it = row.cells().begin(); it != end; ++it )
+ {
+ if( it->first.type() == Symbol::External )
+ return it->first;
+ }
+ if( tag.marker.type() == Symbol::Slack || tag.marker.type() == Symbol::Error )
+ {
+ if( row.coefficientFor( tag.marker ) < 0.0 )
+ return tag.marker;
+ }
+ if( tag.other.type() == Symbol::Slack || tag.other.type() == Symbol::Error )
+ {
+ if( row.coefficientFor( tag.other ) < 0.0 )
+ return tag.other;
+ }
+ return Symbol();
+ }
+
+ /* Add the row to the tableau using an artificial variable.
+
+ This will return false if the constraint cannot be satisfied.
+
+ */
+ bool addWithArtificialVariable( const Row& row )
+ {
+ // Create and add the artificial variable to the tableau
+ Symbol art( Symbol::Slack, m_id_tick++ );
+ m_rows[ art ] = new Row( row );
+ m_artificial.reset( new Row( row ) );
+
+ // Optimize the artificial objective. This is successful
+ // only if the artificial objective is optimized to zero.
+ optimize( *m_artificial );
+ bool success = nearZero( m_artificial->constant() );
+ m_artificial.reset();
+
+ // If the artificial variable is not basic, pivot the row so that
+ // it becomes basic. If the row is constant, exit early.
+ RowMap::iterator it = m_rows.find( art );
+ if( it != m_rows.end() )
+ {
+ std::auto_ptr<Row> rowptr( it->second );
+ m_rows.erase( it );
+ if( rowptr->cells().empty() )
+ return success;
+ Symbol entering( anyPivotableSymbol( *rowptr ) );
+ if( entering.type() == Symbol::Invalid )
+ return false; // unsatisfiable (will this ever happen?)
+ rowptr->solveFor( art, entering );
+ substitute( entering, *rowptr );
+ m_rows[ entering ] = rowptr.release();
+ }
+
+ // Remove the artificial variable from the tableau.
+ RowMap::iterator end = m_rows.end();
+ for( it = m_rows.begin(); it != end; ++it )
+ it->second->remove( art );
+ m_objective->remove( art );
+ return success;
+ }
+
+ /* Substitute the parametric symbol with the given row.
+
+ This method will substitute all instances of the parametric symbol
+ in the tableau and the objective function with the given row.
+
+ */
+ void substitute( const Symbol& symbol, const Row& row )
+ {
+ typedef RowMap::iterator iter_t;
+ iter_t end = m_rows.end();
+ for( iter_t it = m_rows.begin(); it != end; ++it )
+ {
+ it->second->substitute( symbol, row );
+ if( it->first.type() != Symbol::External &&
+ it->second->constant() < 0.0 )
+ m_infeasible_rows.push_back( it->first );
+ }
+ m_objective->substitute( symbol, row );
+ if( m_artificial.get() )
+ m_artificial->substitute( symbol, row );
+ }
+
+ /* Optimize the system for the given objective function.
+
+ This method performs iterations of Phase 2 of the simplex method
+ until the objective function reaches a minimum.
+
+ Throws
+ ------
+ InternalSolverError
+ The value of the objective function is unbounded.
+
+ */
+ void optimize( const Row& objective )
+ {
+ while( true )
+ {
+ Symbol entering( getEnteringSymbol( objective ) );
+ if( entering.type() == Symbol::Invalid )
+ return;
+ RowMap::iterator it = getLeavingRow( entering );
+ if( it == m_rows.end() )
+ throw InternalSolverError( "The objective is unbounded." );
+ // pivot the entering symbol into the basis
+ Symbol leaving( it->first );
+ Row* row = it->second;
+ m_rows.erase( it );
+ row->solveFor( leaving, entering );
+ substitute( entering, *row );
+ m_rows[ entering ] = row;
+ }
+ }
+
+ /* Optimize the system using the dual of the simplex method.
+
+ The current state of the system should be such that the objective
+ function is optimal, but not feasible. This method will perform
+ an iteration of the dual simplex method to make the solution both
+ optimal and feasible.
+
+ Throws
+ ------
+ InternalSolverError
+ The system cannot be dual optimized.
+
+ */
+ void dualOptimize()
+ {
+ while( !m_infeasible_rows.empty() )
+ {
+
+ Symbol leaving( m_infeasible_rows.back() );
+ m_infeasible_rows.pop_back();
+ RowMap::iterator it = m_rows.find( leaving );
+ if( it != m_rows.end() && !nearZero( it->second->constant() ) &&
+ it->second->constant() < 0.0 )
+ {
+ Symbol entering( getDualEnteringSymbol( *it->second ) );
+ if( entering.type() == Symbol::Invalid )
+ throw InternalSolverError( "Dual optimize failed." );
+ // pivot the entering symbol into the basis
+ Row* row = it->second;
+ m_rows.erase( it );
+ row->solveFor( leaving, entering );
+ substitute( entering, *row );
+ m_rows[ entering ] = row;
+ }
+ }
+ }
+
+ /* Compute the entering variable for a pivot operation.
+
+ This method will return first symbol in the objective function which
+ is non-dummy and has a coefficient less than zero. If no symbol meets
+ the criteria, it means the objective function is at a minimum, and an
+ invalid symbol is returned.
+
+ */
+ Symbol getEnteringSymbol( const Row& objective )
+ {
+ typedef Row::CellMap::const_iterator iter_t;
+ iter_t end = objective.cells().end();
+ for( iter_t it = objective.cells().begin(); it != end; ++it )
+ {
+ if( it->first.type() != Symbol::Dummy && it->second < 0.0 )
+ return it->first;
+ }
+ return Symbol();
+ }
+
+ /* Compute the entering symbol for the dual optimize operation.
+
+ This method will return the symbol in the row which has a positive
+ coefficient and yields the minimum ratio for its respective symbol
+ in the objective function. The provided row *must* be infeasible.
+ If no symbol is found which meats the criteria, an invalid symbol
+ is returned.
+
+ */
+ Symbol getDualEnteringSymbol( const Row& row )
+ {
+ typedef Row::CellMap::const_iterator iter_t;
+ Symbol entering;
+ double ratio = std::numeric_limits<double>::max();
+ iter_t end = row.cells().end();
+ for( iter_t it = row.cells().begin(); it != end; ++it )
+ {
+ if( it->second > 0.0 && it->first.type() != Symbol::Dummy )
+ {
+ double coeff = m_objective->coefficientFor( it->first );
+ double r = coeff / it->second;
+ if( r < ratio )
+ {
+ ratio = r;
+ entering = it->first;
+ }
+ }
+ }
+ return entering;
+ }
+
+ /* Get the first Slack or Error symbol in the row.
+
+ If no such symbol is present, and Invalid symbol will be returned.
+
+ */
+ Symbol anyPivotableSymbol( const Row& row )
+ {
+ typedef Row::CellMap::const_iterator iter_t;
+ iter_t end = row.cells().end();
+ for( iter_t it = row.cells().begin(); it != end; ++it )
+ {
+ const Symbol& sym( it->first );
+ if( sym.type() == Symbol::Slack || sym.type() == Symbol::Error )
+ return sym;
+ }
+ return Symbol();
+ }
+
+ /* Compute the row which holds the exit symbol for a pivot.
+
+ This method will return an iterator to the row in the row map
+ which holds the exit symbol. If no appropriate exit symbol is
+ found, the end() iterator will be returned. This indicates that
+ the objective function is unbounded.
+
+ */
+ RowMap::iterator getLeavingRow( const Symbol& entering )
+ {
+ typedef RowMap::iterator iter_t;
+ double ratio = std::numeric_limits<double>::max();
+ iter_t end = m_rows.end();
+ iter_t found = m_rows.end();
+ for( iter_t it = m_rows.begin(); it != end; ++it )
+ {
+ if( it->first.type() != Symbol::External )
+ {
+ double temp = it->second->coefficientFor( entering );
+ if( temp < 0.0 )
+ {
+ double temp_ratio = -it->second->constant() / temp;
+ if( temp_ratio < ratio )
+ {
+ ratio = temp_ratio;
+ found = it;
+ }
+ }
+ }
+ }
+ return found;
+ }
+
+ /* Compute the leaving row for a marker variable.
+
+ This method will return an iterator to the row in the row map
+ which holds the given marker variable. The row will be chosen
+ according to the following precedence:
+
+ 1) The row with a restricted basic varible and a negative coefficient
+ for the marker with the smallest ratio of -constant / coefficient.
+
+ 2) The row with a restricted basic variable and the smallest ratio
+ of constant / coefficient.
+
+ 3) The last unrestricted row which contains the marker.
+
+ If the marker does not exist in any row, the row map end() iterator
+ will be returned. This indicates an internal solver error since
+ the marker *should* exist somewhere in the tableau.
+
+ */
+ RowMap::iterator getMarkerLeavingRow( const Symbol& marker )
+ {
+ const double dmax = std::numeric_limits<double>::max();
+ typedef RowMap::iterator iter_t;
+ double r1 = dmax;
+ double r2 = dmax;
+ iter_t end = m_rows.end();
+ iter_t first = end;
+ iter_t second = end;
+ iter_t third = end;
+ for( iter_t it = m_rows.begin(); it != end; ++it )
+ {
+ double c = it->second->coefficientFor( marker );
+ if( c == 0.0 )
+ continue;
+ if( it->first.type() == Symbol::External )
+ {
+ third = it;
+ }
+ else if( c < 0.0 )
+ {
+ double r = -it->second->constant() / c;
+ if( r < r1 )
+ {
+ r1 = r;
+ first = it;
+ }
+ }
+ else
+ {
+ double r = it->second->constant() / c;
+ if( r < r2 )
+ {
+ r2 = r;
+ second = it;
+ }
+ }
+ }
+ if( first != end )
+ return first;
+ if( second != end )
+ return second;
+ return third;
+ }
+
+ /* Remove the effects of a constraint on the objective function.
+
+ */
+ void removeConstraintEffects( const Constraint& cn, const Tag& tag )
+ {
+ if( tag.marker.type() == Symbol::Error )
+ removeMarkerEffects( tag.marker, cn.strength() );
+ if( tag.other.type() == Symbol::Error )
+ removeMarkerEffects( tag.other, cn.strength() );
+ }
+
+ /* Remove the effects of an error marker on the objective function.
+
+ */
+ void removeMarkerEffects( const Symbol& marker, double strength )
+ {
+ RowMap::iterator row_it = m_rows.find( marker );
+ if( row_it != m_rows.end() )
+ m_objective->insert( *row_it->second, -strength );
+ else
+ m_objective->insert( marker, -strength );
+ }
+
+ /* Test whether a row is composed of all dummy variables.
+
+ */
+ bool allDummies( const Row& row )
+ {
+ typedef Row::CellMap::const_iterator iter_t;
+ iter_t end = row.cells().end();
+ for( iter_t it = row.cells().begin(); it != end; ++it )
+ {
+ if( it->first.type() != Symbol::Dummy )
+ return false;
+ }
+ return true;
+ }
+
+ CnMap m_cns;
+ RowMap m_rows;
+ VarMap m_vars;
+ EditMap m_edits;
+ std::vector<Symbol> m_infeasible_rows;
+ std::auto_ptr<Row> m_objective;
+ std::auto_ptr<Row> m_artificial;
+ Symbol::Id m_id_tick;
+};
+
+} // namespace impl
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/strength.h b/contrib/python/kiwisolver/py2/kiwi/strength.h
new file mode 100644
index 00000000000..b077f3e17c1
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/strength.h
@@ -0,0 +1,44 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <algorithm>
+
+
+namespace kiwi
+{
+
+namespace strength
+{
+
+inline double create( double a, double b, double c, double w = 1.0 )
+{
+ double result = 0.0;
+ result += std::max( 0.0, std::min( 1000.0, a * w ) ) * 1000000.0;
+ result += std::max( 0.0, std::min( 1000.0, b * w ) ) * 1000.0;
+ result += std::max( 0.0, std::min( 1000.0, c * w ) );
+ return result;
+}
+
+
+const double required = create( 1000.0, 1000.0, 1000.0 );
+
+const double strong = create( 1.0, 0.0, 0.0 );
+
+const double medium = create( 0.0, 1.0, 0.0 );
+
+const double weak = create( 0.0, 0.0, 1.0 );
+
+
+inline double clip( double value )
+{
+ return std::max( 0.0, std::min( required, value ) );
+}
+
+} // namespace strength
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/symbol.h b/contrib/python/kiwisolver/py2/kiwi/symbol.h
new file mode 100644
index 00000000000..b971efbdd25
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/symbol.h
@@ -0,0 +1,68 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+
+
+namespace kiwi
+{
+
+namespace impl
+{
+
+class Symbol
+{
+
+public:
+
+ typedef unsigned long long Id;
+
+ enum Type
+ {
+ Invalid,
+ External,
+ Slack,
+ Error,
+ Dummy
+ };
+
+ Symbol() : m_id( 0 ), m_type( Invalid ) {}
+
+ Symbol( Type type, Id id ) : m_id( id ), m_type( type ) {}
+
+ ~Symbol() {}
+
+ Id id() const
+ {
+ return m_id;
+ }
+
+ Type type() const
+ {
+ return m_type;
+ }
+
+private:
+
+ Id m_id;
+ Type m_type;
+
+ friend bool operator<( const Symbol& lhs, const Symbol& rhs )
+ {
+ return lhs.m_id < rhs.m_id;
+ }
+
+ friend bool operator==( const Symbol& lhs, const Symbol& rhs )
+ {
+ return lhs.m_id == rhs.m_id;
+ }
+
+};
+
+} // namespace impl
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/symbolics.h b/contrib/python/kiwisolver/py2/kiwi/symbolics.h
new file mode 100644
index 00000000000..51ac6a8a37b
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/symbolics.h
@@ -0,0 +1,685 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <vector>
+#include "constraint.h"
+#include "expression.h"
+#include "term.h"
+#include "variable.h"
+
+
+namespace kiwi
+{
+
+// Variable multiply, divide, and unary invert
+
+inline
+Term operator*( const Variable& variable, double coefficient )
+{
+ return Term( variable, coefficient );
+}
+
+
+inline
+Term operator/( const Variable& variable, double denominator )
+{
+ return variable * ( 1.0 / denominator );
+}
+
+
+inline
+Term operator-( const Variable& variable )
+{
+ return variable * -1.0;
+}
+
+
+// Term multiply, divide, and unary invert
+
+inline
+Term operator*( const Term& term, double coefficient )
+{
+ return Term( term.variable(), term.coefficient() * coefficient );
+}
+
+
+inline
+Term operator/( const Term& term, double denominator )
+{
+ return term * ( 1.0 / denominator );
+}
+
+
+inline
+Term operator-( const Term& term )
+{
+ return term * -1.0;
+}
+
+
+// Expression multiply, divide, and unary invert
+
+inline
+Expression operator*( const Expression& expression, double coefficient )
+{
+ std::vector<Term> terms;
+ terms.reserve( expression.terms().size() );
+ typedef std::vector<Term>::const_iterator iter_t;
+ iter_t begin = expression.terms().begin();
+ iter_t end = expression.terms().end();
+ for( iter_t it = begin; it != end; ++it )
+ terms.push_back( ( *it ) * coefficient );
+ return Expression( terms, expression.constant() * coefficient );
+}
+
+
+inline
+Expression operator/( const Expression& expression, double denominator )
+{
+ return expression * ( 1.0 / denominator );
+}
+
+
+inline
+Expression operator-( const Expression& expression )
+{
+ return expression * -1.0;
+}
+
+
+// Double multiply
+
+inline
+Expression operator*( double coefficient, const Expression& expression )
+{
+ return expression * coefficient;
+}
+
+
+inline
+Term operator*( double coefficient, const Term& term )
+{
+ return term * coefficient;
+}
+
+
+inline
+Term operator*( double coefficient, const Variable& variable )
+{
+ return variable * coefficient;
+}
+
+
+// Expression add and subtract
+
+inline
+Expression operator+( const Expression& first, const Expression& second )
+{
+ std::vector<Term> terms;
+ terms.reserve( first.terms().size() + second.terms().size() );
+ terms.insert( terms.begin(), first.terms().begin(), first.terms().end() );
+ terms.insert( terms.end(), second.terms().begin(), second.terms().end() );
+ return Expression( terms, first.constant() + second.constant() );
+}
+
+
+inline
+Expression operator+( const Expression& first, const Term& second )
+{
+ std::vector<Term> terms;
+ terms.reserve( first.terms().size() + 1 );
+ terms.insert( terms.begin(), first.terms().begin(), first.terms().end() );
+ terms.push_back( second );
+ return Expression( terms, first.constant() );
+}
+
+
+inline
+Expression operator+( const Expression& expression, const Variable& variable )
+{
+ return expression + Term( variable );
+}
+
+
+inline
+Expression operator+( const Expression& expression, double constant )
+{
+ return Expression( expression.terms(), expression.constant() + constant );
+}
+
+
+inline
+Expression operator-( const Expression& first, const Expression& second )
+{
+ return first + -second;
+}
+
+
+inline
+Expression operator-( const Expression& expression, const Term& term )
+{
+ return expression + -term;
+}
+
+
+inline
+Expression operator-( const Expression& expression, const Variable& variable )
+{
+ return expression + -variable;
+}
+
+
+inline
+Expression operator-( const Expression& expression, double constant )
+{
+ return expression + -constant;
+}
+
+
+// Term add and subtract
+
+inline
+Expression operator+( const Term& term, const Expression& expression )
+{
+ return expression + term;
+}
+
+
+inline
+Expression operator+( const Term& first, const Term& second )
+{
+ std::vector<Term> terms;
+ terms.reserve( 2 );
+ terms.push_back( first );
+ terms.push_back( second );
+ return Expression( terms );
+}
+
+
+inline
+Expression operator+( const Term& term, const Variable& variable )
+{
+ return term + Term( variable );
+}
+
+
+inline
+Expression operator+( const Term& term, double constant )
+{
+ return Expression( term, constant );
+}
+
+
+inline
+Expression operator-( const Term& term, const Expression& expression )
+{
+ return -expression + term;
+}
+
+
+inline
+Expression operator-( const Term& first, const Term& second )
+{
+ return first + -second;
+}
+
+
+inline
+Expression operator-( const Term& term, const Variable& variable )
+{
+ return term + -variable;
+}
+
+
+inline
+Expression operator-( const Term& term, double constant )
+{
+ return term + -constant;
+}
+
+
+// Variable add and subtract
+
+inline
+Expression operator+( const Variable& variable, const Expression& expression )
+{
+ return expression + variable;
+}
+
+
+inline
+Expression operator+( const Variable& variable, const Term& term )
+{
+ return term + variable;
+}
+
+
+inline
+Expression operator+( const Variable& first, const Variable& second )
+{
+ return Term( first ) + second;
+}
+
+
+inline
+Expression operator+( const Variable& variable, double constant )
+{
+ return Term( variable ) + constant;
+}
+
+
+inline
+Expression operator-( const Variable& variable, const Expression& expression )
+{
+ return variable + -expression;
+}
+
+
+inline
+Expression operator-( const Variable& variable, const Term& term )
+{
+ return variable + -term;
+}
+
+
+inline
+Expression operator-( const Variable& first, const Variable& second )
+{
+ return first + -second;
+}
+
+
+inline
+Expression operator-( const Variable& variable, double constant )
+{
+ return variable + -constant;
+}
+
+
+// Double add and subtract
+
+inline
+Expression operator+( double constant, const Expression& expression )
+{
+ return expression + constant;
+}
+
+
+inline
+Expression operator+( double constant, const Term& term )
+{
+ return term + constant;
+}
+
+
+inline
+Expression operator+( double constant, const Variable& variable )
+{
+ return variable + constant;
+}
+
+
+inline
+Expression operator-( double constant, const Expression& expression )
+{
+ return -expression + constant;
+}
+
+
+inline
+Expression operator-( double constant, const Term& term )
+{
+ return -term + constant;
+}
+
+
+inline
+Expression operator-( double constant, const Variable& variable )
+{
+ return -variable + constant;
+}
+
+
+// Expression relations
+
+inline
+Constraint operator==( const Expression& first, const Expression& second )
+{
+ return Constraint( first - second, OP_EQ );
+}
+
+
+inline
+Constraint operator==( const Expression& expression, const Term& term )
+{
+ return expression == Expression( term );
+}
+
+
+inline
+Constraint operator==( const Expression& expression, const Variable& variable )
+{
+ return expression == Term( variable );
+}
+
+
+inline
+Constraint operator==( const Expression& expression, double constant )
+{
+ return expression == Expression( constant );
+}
+
+
+inline
+Constraint operator<=( const Expression& first, const Expression& second )
+{
+ return Constraint( first - second, OP_LE );
+}
+
+
+inline
+Constraint operator<=( const Expression& expression, const Term& term )
+{
+ return expression <= Expression( term );
+}
+
+
+inline
+Constraint operator<=( const Expression& expression, const Variable& variable )
+{
+ return expression <= Term( variable );
+}
+
+
+inline
+Constraint operator<=( const Expression& expression, double constant )
+{
+ return expression <= Expression( constant );
+}
+
+
+inline
+Constraint operator>=( const Expression& first, const Expression& second )
+{
+ return Constraint( first - second, OP_GE );
+}
+
+
+inline
+Constraint operator>=( const Expression& expression, const Term& term )
+{
+ return expression >= Expression( term );
+}
+
+
+inline
+Constraint operator>=( const Expression& expression, const Variable& variable )
+{
+ return expression >= Term( variable );
+}
+
+
+inline
+Constraint operator>=( const Expression& expression, double constant )
+{
+ return expression >= Expression( constant );
+}
+
+
+// Term relations
+
+inline
+Constraint operator==( const Term& term, const Expression& expression )
+{
+ return expression == term;
+}
+
+
+inline
+Constraint operator==( const Term& first, const Term& second )
+{
+ return Expression( first ) == second;
+}
+
+
+inline
+Constraint operator==( const Term& term, const Variable& variable )
+{
+ return Expression( term ) == variable;
+}
+
+
+inline
+Constraint operator==( const Term& term, double constant )
+{
+ return Expression( term ) == constant;
+}
+
+
+inline
+Constraint operator<=( const Term& term, const Expression& expression )
+{
+ return expression >= term;
+}
+
+
+inline
+Constraint operator<=( const Term& first, const Term& second )
+{
+ return Expression( first ) <= second;
+}
+
+
+inline
+Constraint operator<=( const Term& term, const Variable& variable )
+{
+ return Expression( term ) <= variable;
+}
+
+
+inline
+Constraint operator<=( const Term& term, double constant )
+{
+ return Expression( term ) <= constant;
+}
+
+
+inline
+Constraint operator>=( const Term& term, const Expression& expression )
+{
+ return expression <= term;
+}
+
+
+inline
+Constraint operator>=( const Term& first, const Term& second )
+{
+ return Expression( first ) >= second;
+}
+
+
+inline
+Constraint operator>=( const Term& term, const Variable& variable )
+{
+ return Expression( term ) >= variable;
+}
+
+
+inline
+Constraint operator>=( const Term& term, double constant )
+{
+ return Expression( term ) >= constant;
+}
+
+
+// Variable relations
+inline
+Constraint operator==( const Variable& variable, const Expression& expression )
+{
+ return expression == variable;
+}
+
+
+inline
+Constraint operator==( const Variable& variable, const Term& term )
+{
+ return term == variable;
+}
+
+
+inline
+Constraint operator==( const Variable& first, const Variable& second )
+{
+ return Term( first ) == second;
+}
+
+
+inline
+Constraint operator==( const Variable& variable, double constant )
+{
+ return Term( variable ) == constant;
+}
+
+
+inline
+Constraint operator<=( const Variable& variable, const Expression& expression )
+{
+ return expression >= variable;
+}
+
+
+inline
+Constraint operator<=( const Variable& variable, const Term& term )
+{
+ return term >= variable;
+}
+
+
+inline
+Constraint operator<=( const Variable& first, const Variable& second )
+{
+ return Term( first ) <= second;
+}
+
+
+inline
+Constraint operator<=( const Variable& variable, double constant )
+{
+ return Term( variable ) <= constant;
+}
+
+
+inline
+Constraint operator>=( const Variable& variable, const Expression& expression )
+{
+ return expression <= variable;
+}
+
+
+inline
+Constraint operator>=( const Variable& variable, const Term& term )
+{
+ return term <= variable;
+}
+
+
+inline
+Constraint operator>=( const Variable& first, const Variable& second )
+{
+ return Term( first ) >= second;
+}
+
+
+inline
+Constraint operator>=( const Variable& variable, double constant )
+{
+ return Term( variable ) >= constant;
+}
+
+
+// Double relations
+
+inline
+Constraint operator==( double constant, const Expression& expression )
+{
+ return expression == constant;
+}
+
+
+inline
+Constraint operator==( double constant, const Term& term )
+{
+ return term == constant;
+}
+
+
+inline
+Constraint operator==( double constant, const Variable& variable )
+{
+ return variable == constant;
+}
+
+
+inline
+Constraint operator<=( double constant, const Expression& expression )
+{
+ return expression >= constant;
+}
+
+
+inline
+Constraint operator<=( double constant, const Term& term )
+{
+ return term >= constant;
+}
+
+
+inline
+Constraint operator<=( double constant, const Variable& variable )
+{
+ return variable >= constant;
+}
+
+
+inline
+Constraint operator>=( double constant, const Expression& expression )
+{
+ return expression <= constant;
+}
+
+
+inline
+Constraint operator>=( double constant, const Term& term )
+{
+ return term <= constant;
+}
+
+
+inline
+Constraint operator>=( double constant, const Variable& variable )
+{
+ return variable <= constant;
+}
+
+
+// Constraint strength modifier
+
+inline
+Constraint operator|( const Constraint& constraint, double strength )
+{
+ return Constraint( constraint, strength );
+}
+
+
+inline
+Constraint operator|( double strength, const Constraint& constraint )
+{
+ return constraint | strength;
+}
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/term.h b/contrib/python/kiwisolver/py2/kiwi/term.h
new file mode 100644
index 00000000000..1ee962287cc
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/term.h
@@ -0,0 +1,51 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <utility>
+#include "variable.h"
+
+
+namespace kiwi
+{
+
+class Term
+{
+
+public:
+
+ Term( const Variable& variable, double coefficient = 1.0 ) :
+ m_variable( variable ), m_coefficient( coefficient ) {}
+
+ // to facilitate efficient map -> vector copies
+ Term( const std::pair<const Variable, double>& pair ) :
+ m_variable( pair.first ), m_coefficient( pair.second ) {}
+
+ ~Term() {}
+
+ const Variable& variable() const
+ {
+ return m_variable;
+ }
+
+ double coefficient() const
+ {
+ return m_coefficient;
+ }
+
+ double value() const
+ {
+ return m_coefficient * m_variable.value();
+ }
+
+private:
+
+ Variable m_variable;
+ double m_coefficient;
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/util.h b/contrib/python/kiwisolver/py2/kiwi/util.h
new file mode 100644
index 00000000000..0d36a33eb15
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/util.h
@@ -0,0 +1,25 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+
+
+namespace kiwi
+{
+
+namespace impl
+{
+
+inline bool nearZero( double value )
+{
+ const double eps = 1.0e-8;
+ return value < 0.0 ? -value < eps : value < eps;
+}
+
+} // namespace impl
+
+} // namespace
diff --git a/contrib/python/kiwisolver/py2/kiwi/variable.h b/contrib/python/kiwisolver/py2/kiwi/variable.h
new file mode 100644
index 00000000000..eaee93f2a13
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/variable.h
@@ -0,0 +1,121 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <memory>
+#include <string>
+#include "shareddata.h"
+
+
+namespace kiwi
+{
+
+class Variable
+{
+
+public:
+
+ class Context
+ {
+ public:
+ Context() {}
+ virtual ~Context() {} // LCOV_EXCL_LINE
+ };
+
+ Variable( Context* context = 0 ) :
+ m_data( new VariableData( "", context ) ) {}
+
+ Variable( const std::string& name, Context* context = 0 ) :
+ m_data( new VariableData( name, context ) ) {}
+
+ Variable( const char* name, Context* context = 0 ) :
+ m_data( new VariableData( name, context ) ) {}
+
+ ~Variable() {}
+
+ const std::string& name() const
+ {
+ return m_data->m_name;
+ }
+
+ void setName( const char* name )
+ {
+ m_data->m_name = name;
+ }
+
+ void setName( const std::string& name )
+ {
+ m_data->m_name = name;
+ }
+
+ Context* context() const
+ {
+ return m_data->m_context.get();
+ }
+
+ void setContext( Context* context )
+ {
+ m_data->m_context.reset( context );
+ }
+
+ double value() const
+ {
+ return m_data->m_value;
+ }
+
+ void setValue( double value )
+ {
+ m_data->m_value = value;
+ }
+
+ // operator== is used for symbolics
+ bool equals( const Variable& other )
+ {
+ return m_data == other.m_data;
+ }
+
+private:
+
+ class VariableData : public SharedData
+ {
+
+ public:
+
+ VariableData( const std::string& name, Context* context ) :
+ SharedData(),
+ m_name( name ),
+ m_context( context ),
+ m_value( 0.0 ) {}
+
+ VariableData( const char* name, Context* context ) :
+ SharedData(),
+ m_name( name ),
+ m_context( context ),
+ m_value( 0.0 ) {}
+
+ ~VariableData() {}
+
+ std::string m_name;
+ std::auto_ptr<Context> m_context;
+ double m_value;
+
+ private:
+
+ VariableData( const VariableData& other );
+
+ VariableData& operator=( const VariableData& other );
+ };
+
+ SharedDataPtr<VariableData> m_data;
+
+ friend bool operator<( const Variable& lhs, const Variable& rhs )
+ {
+ return lhs.m_data < rhs.m_data;
+ }
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py2/kiwi/version.h b/contrib/python/kiwisolver/py2/kiwi/version.h
new file mode 100644
index 00000000000..197f3ce1869
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/kiwi/version.h
@@ -0,0 +1,14 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+
+#define KIWI_MAJOR_VERSION 1
+#define KIWI_MINOR_VERSION 0
+#define KIWI_MICRO_VERSION 1
+#define KIWI_VERSION_HEX 0x010001
+#define KIWI_VERSION "1.1.0"
diff --git a/contrib/python/kiwisolver/py2/py/constraint.cpp b/contrib/python/kiwisolver/py2/py/constraint.cpp
new file mode 100644
index 00000000000..2fbdd0aeb83
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/py/constraint.cpp
@@ -0,0 +1,299 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <algorithm>
+#include <sstream>
+#include <Python.h>
+#include <kiwi/kiwi.h>
+#include "pythonhelpers.h"
+#include "types.h"
+#include "util.h"
+
+
+using namespace PythonHelpers;
+
+
+static PyObject*
+Constraint_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
+{
+ static const char *kwlist[] = { "expression", "op", "strength", 0 };
+ PyObject* pyexpr;
+ PyObject* pyop;
+ PyObject* pystrength = 0;
+ if( !PyArg_ParseTupleAndKeywords(
+ args, kwargs, "OO|O:__new__", const_cast<char**>( kwlist ),
+ &pyexpr, &pyop, &pystrength ) )
+ return 0;
+ if( !Expression::TypeCheck( pyexpr ) )
+ return py_expected_type_fail( pyexpr, "Expression" );
+ kiwi::RelationalOperator op;
+ if( !convert_to_relational_op( pyop, op ) )
+ return 0;
+ double strength = kiwi::strength::required;
+ if( pystrength && !convert_to_strength( pystrength, strength ) )
+ return 0;
+ PyObjectPtr pycn( PyType_GenericNew( type, args, kwargs ) );
+ if( !pycn )
+ return 0;
+ Constraint* cn = reinterpret_cast<Constraint*>( pycn.get() );
+ cn->expression = reduce_expression( pyexpr );
+ if( !cn->expression )
+ return 0;
+ kiwi::Expression expr( convert_to_kiwi_expression( cn->expression ) );
+ new( &cn->constraint ) kiwi::Constraint( expr, op, strength );
+ return pycn.release();
+}
+
+
+static void
+Constraint_clear( Constraint* self )
+{
+ Py_CLEAR( self->expression );
+}
+
+
+static int
+Constraint_traverse( Constraint* self, visitproc visit, void* arg )
+{
+ Py_VISIT( self->expression );
+ return 0;
+}
+
+
+static void
+Constraint_dealloc( Constraint* self )
+{
+ PyObject_GC_UnTrack( self );
+ Constraint_clear( self );
+ self->constraint.~Constraint();
+ Py_TYPE( self )->tp_free( pyobject_cast( self ) );
+}
+
+
+static PyObject*
+Constraint_repr( Constraint* self )
+{
+ std::stringstream stream;
+ Expression* expr = reinterpret_cast<Expression*>( self->expression );
+ Py_ssize_t size = PyTuple_GET_SIZE( expr->terms );
+ for( Py_ssize_t i = 0; i < size; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( expr->terms, i );
+ Term* term = reinterpret_cast<Term*>( item );
+ stream << term->coefficient << " * ";
+ stream << reinterpret_cast<Variable*>( term->variable )->variable.name();
+ stream << " + ";
+ }
+ stream << expr->constant;
+ switch( self->constraint.op() )
+ {
+ case kiwi::OP_EQ:
+ stream << " == 0";
+ break;
+ case kiwi::OP_LE:
+ stream << " <= 0";
+ break;
+ case kiwi::OP_GE:
+ stream << " >= 0";
+ break;
+ }
+ stream << " | strength = " << self->constraint.strength();
+ return FROM_STRING( stream.str().c_str() );
+}
+
+
+static PyObject*
+Constraint_expression( Constraint* self )
+{
+ return newref( self->expression );
+}
+
+
+static PyObject*
+Constraint_op( Constraint* self )
+{
+ PyObject* res = 0;
+ switch( self->constraint.op() )
+ {
+ case kiwi::OP_EQ:
+ res = FROM_STRING( "==" );
+ break;
+ case kiwi::OP_LE:
+ res = FROM_STRING( "<=" );
+ break;
+ case kiwi::OP_GE:
+ res = FROM_STRING( ">=" );
+ break;
+ }
+ return res;
+}
+
+
+static PyObject*
+Constraint_strength( Constraint* self )
+{
+ return PyFloat_FromDouble( self->constraint.strength() );
+}
+
+
+static PyObject*
+Constraint_or( PyObject* pyoldcn, PyObject* value )
+{
+ if( !Constraint::TypeCheck( pyoldcn ) )
+ std::swap( pyoldcn, value );
+ double strength;
+ if( !convert_to_strength( value, strength ) )
+ return 0;
+ PyObject* pynewcn = PyType_GenericNew( &Constraint_Type, 0, 0 );
+ if( !pynewcn )
+ return 0;
+ Constraint* oldcn = reinterpret_cast<Constraint*>( pyoldcn );
+ Constraint* newcn = reinterpret_cast<Constraint*>( pynewcn );
+ newcn->expression = newref( oldcn->expression );
+ new( &newcn->constraint ) kiwi::Constraint( oldcn->constraint, strength );
+ return pynewcn;
+}
+
+
+static PyMethodDef
+Constraint_methods[] = {
+ { "expression", ( PyCFunction )Constraint_expression, METH_NOARGS,
+ "Get the expression object for the constraint." },
+ { "op", ( PyCFunction )Constraint_op, METH_NOARGS,
+ "Get the relational operator for the constraint." },
+ { "strength", ( PyCFunction )Constraint_strength, METH_NOARGS,
+ "Get the strength for the constraint." },
+ { 0 } // sentinel
+};
+
+
+static PyNumberMethods
+Constraint_as_number = {
+ 0, /* nb_add */
+ 0, /* nb_subtract */
+ 0, /* nb_multiply */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_divide */
+#endif
+ 0, /* nb_remainder */
+ 0, /* nb_divmod */
+ 0, /* nb_power */
+ 0, /* nb_negative */
+ 0, /* nb_positive */
+ 0, /* nb_absolute */
+#if PY_MAJOR_VERSION >= 3
+ 0, /* nb_bool */
+#else
+ 0, /* nb_nonzero */
+#endif
+ 0, /* nb_invert */
+ 0, /* nb_lshift */
+ 0, /* nb_rshift */
+ 0, /* nb_and */
+ 0, /* nb_xor */
+ (binaryfunc)Constraint_or, /* nb_or */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_coerce */
+#endif
+ 0, /* nb_int */
+ 0, /* nb_long */
+ 0, /* nb_float */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_oct */
+ 0, /* nb_hex */
+#endif
+ 0, /* nb_inplace_add */
+ 0, /* nb_inplace_subtract */
+ 0, /* nb_inplace_multiply */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_inplace_divide */
+#endif
+ 0, /* nb_inplace_remainder */
+ 0, /* nb_inplace_power */
+ 0, /* nb_inplace_lshift */
+ 0, /* nb_inplace_rshift */
+ 0, /* nb_inplace_and */
+ 0, /* nb_inplace_xor */
+ 0, /* nb_inplace_or */
+ (binaryfunc)0, /* nb_floor_divide */
+ (binaryfunc)0, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+#if PY_VERSION_HEX >= 0x02050000
+ (unaryfunc)0, /* nb_index */
+#endif
+#if PY_VERSION_HEX >= 0x03050000
+ (binaryfunc)0, /* nb_matrix_multiply */
+ (binaryfunc)0, /* nb_inplace_matrix_multiply */
+#endif
+};
+
+
+PyTypeObject Constraint_Type = {
+ PyVarObject_HEAD_INIT( &PyType_Type, 0 )
+ "kiwisolver.Constraint", /* tp_name */
+ sizeof( Constraint ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Constraint_dealloc, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03050000
+ ( PyAsyncMethods* )0, /* tp_as_async */
+#elif PY_VERSION_HEX >= 0x03000000
+ ( void* ) 0, /* tp_reserved */
+#else
+ ( cmpfunc )0, /* tp_compare */
+#endif
+ (reprfunc)Constraint_repr, /* tp_repr */
+ (PyNumberMethods*)&Constraint_as_number,/* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+#if PY_MAJOR_VERSION >= 3
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, /* tp_flags */
+#else
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+#endif
+ 0, /* Documentation string */
+ (traverseproc)Constraint_traverse, /* tp_traverse */
+ (inquiry)Constraint_clear, /* tp_clear */
+ (richcmpfunc)0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)Constraint_methods,/* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)Constraint_new, /* tp_new */
+ (freefunc)PyObject_GC_Del, /* tp_free */
+ (inquiry)0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ (destructor)0 /* tp_del */
+};
+
+
+int import_constraint()
+{
+ return PyType_Ready( &Constraint_Type );
+}
diff --git a/contrib/python/kiwisolver/py2/py/expression.cpp b/contrib/python/kiwisolver/py2/py/expression.cpp
new file mode 100644
index 00000000000..5cd34e4c120
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/py/expression.cpp
@@ -0,0 +1,326 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <sstream>
+#include <Python.h>
+#include "pythonhelpers.h"
+#include "symbolics.h"
+#include "types.h"
+#include "util.h"
+
+
+using namespace PythonHelpers;
+
+
+static PyObject*
+Expression_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
+{
+ static const char *kwlist[] = { "terms", "constant", 0 };
+ PyObject* pyterms;
+ PyObject* pyconstant = 0;
+ if( !PyArg_ParseTupleAndKeywords(
+ args, kwargs, "O|O:__new__", const_cast<char**>( kwlist ),
+ &pyterms, &pyconstant ) )
+ return 0;
+ PyObjectPtr terms( PySequence_Tuple( pyterms ) );
+ if( !terms )
+ return 0;
+ Py_ssize_t end = PyTuple_GET_SIZE( terms.get() );
+ for( Py_ssize_t i = 0; i < end; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( terms.get(), i );
+ if( !Term::TypeCheck( item ) )
+ return py_expected_type_fail( item, "Term" );
+ }
+ double constant = 0.0;
+ if( pyconstant && !convert_to_double( pyconstant, constant ) )
+ return 0;
+ PyObject* pyexpr = PyType_GenericNew( type, args, kwargs );
+ if( !pyexpr )
+ return 0;
+ Expression* self = reinterpret_cast<Expression*>( pyexpr );
+ self->terms = terms.release();
+ self->constant = constant;
+ return pyexpr;
+}
+
+
+static void
+Expression_clear( Expression* self )
+{
+ Py_CLEAR( self->terms );
+}
+
+
+static int
+Expression_traverse( Expression* self, visitproc visit, void* arg )
+{
+ Py_VISIT( self->terms );
+ return 0;
+}
+
+
+static void
+Expression_dealloc( Expression* self )
+{
+ PyObject_GC_UnTrack( self );
+ Expression_clear( self );
+ Py_TYPE( self )->tp_free( pyobject_cast( self ) );
+}
+
+
+static PyObject*
+Expression_repr( Expression* self )
+{
+ std::stringstream stream;
+ Py_ssize_t end = PyTuple_GET_SIZE( self->terms );
+ for( Py_ssize_t i = 0; i < end; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( self->terms, i );
+ Term* term = reinterpret_cast<Term*>( item );
+ stream << term->coefficient << " * ";
+ stream << reinterpret_cast<Variable*>( term->variable )->variable.name();
+ stream << " + ";
+ }
+ stream << self->constant;
+ return FROM_STRING( stream.str().c_str() );
+}
+
+
+static PyObject*
+Expression_terms( Expression* self )
+{
+ return newref( self->terms );
+}
+
+
+static PyObject*
+Expression_constant( Expression* self )
+{
+ return PyFloat_FromDouble( self->constant );
+}
+
+
+static PyObject*
+Expression_value( Expression* self )
+{
+ double result = self->constant;
+ Py_ssize_t size = PyTuple_GET_SIZE( self->terms );
+ for( Py_ssize_t i = 0; i < size; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( self->terms, i );
+ Term* term = reinterpret_cast<Term*>( item );
+ Variable* pyvar = reinterpret_cast<Variable*>( term->variable );
+ result += term->coefficient * pyvar->variable.value();
+ }
+ return PyFloat_FromDouble( result );
+}
+
+
+static PyObject*
+Expression_add( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryAdd, Expression>()( first, second );
+}
+
+
+static PyObject*
+Expression_sub( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinarySub, Expression>()( first, second );
+}
+
+
+static PyObject*
+Expression_mul( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryMul, Expression>()( first, second );
+}
+
+
+static PyObject*
+Expression_div( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryDiv, Expression>()( first, second );
+}
+
+
+static PyObject*
+Expression_neg( PyObject* value )
+{
+ return UnaryInvoke<UnaryNeg, Expression>()( value );
+}
+
+
+static PyObject*
+Expression_richcmp( PyObject* first, PyObject* second, int op )
+{
+ switch( op )
+ {
+ case Py_EQ:
+ return BinaryInvoke<CmpEQ, Expression>()( first, second );
+ case Py_LE:
+ return BinaryInvoke<CmpLE, Expression>()( first, second );
+ case Py_GE:
+ return BinaryInvoke<CmpGE, Expression>()( first, second );
+ default:
+ break;
+ }
+ PyErr_Format(
+ PyExc_TypeError,
+ "unsupported operand type(s) for %s: "
+ "'%.100s' and '%.100s'",
+ pyop_str( op ),
+ first->ob_type->tp_name,
+ second->ob_type->tp_name
+ );
+ return 0;
+}
+
+
+static PyMethodDef
+Expression_methods[] = {
+ { "terms", ( PyCFunction )Expression_terms, METH_NOARGS,
+ "Get the tuple of terms for the expression." },
+ { "constant", ( PyCFunction )Expression_constant, METH_NOARGS,
+ "Get the constant for the expression." },
+ { "value", ( PyCFunction )Expression_value, METH_NOARGS,
+ "Get the value for the expression." },
+ { 0 } // sentinel
+};
+
+
+static PyNumberMethods
+Expression_as_number = {
+ (binaryfunc)Expression_add, /* nb_add */
+ (binaryfunc)Expression_sub, /* nb_subtract */
+ (binaryfunc)Expression_mul, /* nb_multiply */
+#if PY_MAJOR_VERSION < 3
+ (binaryfunc)Expression_div, /* nb_divide */
+#endif
+ 0, /* nb_remainder */
+ 0, /* nb_divmod */
+ 0, /* nb_power */
+ (unaryfunc)Expression_neg, /* nb_negative */
+ 0, /* nb_positive */
+ 0, /* nb_absolute */
+#if PY_MAJOR_VERSION >= 3
+ 0, /* nb_bool */
+#else
+ 0, /* nb_nonzero */
+#endif
+ 0, /* nb_invert */
+ 0, /* nb_lshift */
+ 0, /* nb_rshift */
+ 0, /* nb_and */
+ 0, /* nb_xor */
+ (binaryfunc)0, /* nb_or */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_coerce */
+#endif
+ 0, /* nb_int */
+#if PY_MAJOR_VERSION >= 3
+ (void *)0, /* nb_reserved */
+#else
+ 0, /* nb_long */
+#endif
+ 0, /* nb_float */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_oct */
+ 0, /* nb_hex */
+#endif
+ 0, /* nb_inplace_add */
+ 0, /* nb_inplace_subtract */
+ 0, /* nb_inplace_multiply */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_inplace_divide */
+#endif
+ 0, /* nb_inplace_remainder */
+ 0, /* nb_inplace_power */
+ 0, /* nb_inplace_lshift */
+ 0, /* nb_inplace_rshift */
+ 0, /* nb_inplace_and */
+ 0, /* nb_inplace_xor */
+ 0, /* nb_inplace_or */
+ (binaryfunc)0, /* nb_floor_divide */
+ (binaryfunc)Expression_div, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+#if PY_VERSION_HEX >= 0x02050000
+ (unaryfunc)0, /* nb_index */
+#endif
+#if PY_VERSION_HEX >= 0x03050000
+ (binaryfunc)0, /* nb_matrix_multiply */
+ (binaryfunc)0, /* nb_inplace_matrix_multiply */
+#endif
+};
+
+
+PyTypeObject Expression_Type = {
+ PyVarObject_HEAD_INIT( &PyType_Type, 0 )
+ "kiwisolver.Expression", /* tp_name */
+ sizeof( Expression ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Expression_dealloc, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03050000
+ ( PyAsyncMethods* )0, /* tp_as_async */
+#elif PY_VERSION_HEX >= 0x03000000
+ ( void* ) 0, /* tp_reserved */
+#else
+ ( cmpfunc )0, /* tp_compare */
+#endif
+ (reprfunc)Expression_repr, /* tp_repr */
+ (PyNumberMethods*)&Expression_as_number,/* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+#if PY_MAJOR_VERSION >= 3
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE,
+#else
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+#endif
+ 0, /* Documentation string */
+ (traverseproc)Expression_traverse, /* tp_traverse */
+ (inquiry)Expression_clear, /* tp_clear */
+ (richcmpfunc)Expression_richcmp, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)Expression_methods,/* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)Expression_new, /* tp_new */
+ (freefunc)PyObject_GC_Del, /* tp_free */
+ (inquiry)0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ (destructor)0 /* tp_del */
+};
+
+
+int import_expression()
+{
+ return PyType_Ready( &Expression_Type );
+}
diff --git a/contrib/python/kiwisolver/py2/py/kiwisolver.cpp b/contrib/python/kiwisolver/py2/py/kiwisolver.cpp
new file mode 100644
index 00000000000..54b333a2c8b
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/py/kiwisolver.cpp
@@ -0,0 +1,86 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <Python.h>
+#include <kiwi/kiwi.h>
+#include "pythonhelpers.h"
+#include "types.h"
+
+#define PY_KIWI_VERSION "1.1.0"
+
+using namespace PythonHelpers;
+
+static PyMethodDef
+kiwisolver_methods[] = {
+ { 0 } // Sentinel
+};
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef kiwisolver_moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "kiwisolver",
+ NULL,
+ sizeof( struct module_state ),
+ kiwisolver_methods,
+ NULL
+};
+
+PyMODINIT_FUNC
+PyInit_kiwisolver( void )
+#else
+PyMODINIT_FUNC
+initkiwisolver( void )
+#endif
+{
+#if PY_MAJOR_VERSION >= 3
+ PyObject *mod = PyModule_Create( &kiwisolver_moduledef );
+#else
+ PyObject* mod = Py_InitModule( "kiwisolver", kiwisolver_methods );
+#endif
+ if( !mod )
+ INITERROR;
+ if( import_variable() < 0 )
+ INITERROR;
+ if( import_term() < 0 )
+ INITERROR;
+ if( import_expression() < 0 )
+ INITERROR;
+ if( import_constraint() < 0 )
+ INITERROR;
+ if( import_solver() < 0 )
+ INITERROR;
+ if( import_strength() < 0 )
+ INITERROR;
+ PyObject* kiwiversion = FROM_STRING( KIWI_VERSION );
+ if( !kiwiversion )
+ INITERROR;
+ PyObject* pyversion = FROM_STRING( PY_KIWI_VERSION );
+ if( !pyversion )
+ INITERROR;
+ PyObject* pystrength = PyType_GenericNew( &strength_Type, 0, 0 );
+ if( !pystrength )
+ INITERROR;
+
+ PyModule_AddObject( mod, "__version__", pyversion );
+ PyModule_AddObject( mod, "__kiwi_version__", kiwiversion );
+ PyModule_AddObject( mod, "strength", pystrength );
+ PyModule_AddObject( mod, "Variable", newref( pyobject_cast( &Variable_Type ) ) );
+ PyModule_AddObject( mod, "Term", newref( pyobject_cast( &Term_Type ) ) );
+ PyModule_AddObject( mod, "Expression", newref( pyobject_cast( &Expression_Type ) ) );
+ PyModule_AddObject( mod, "Constraint", newref( pyobject_cast( &Constraint_Type ) ) );
+ PyModule_AddObject( mod, "Solver", newref( pyobject_cast( &Solver_Type ) ) );
+ PyModule_AddObject( mod, "DuplicateConstraint", newref( DuplicateConstraint ) );
+ PyModule_AddObject( mod, "UnsatisfiableConstraint", newref( UnsatisfiableConstraint ) );
+ PyModule_AddObject( mod, "UnknownConstraint", newref( UnknownConstraint ) );
+ PyModule_AddObject( mod, "DuplicateEditVariable", newref( DuplicateEditVariable ) );
+ PyModule_AddObject( mod, "UnknownEditVariable", newref( UnknownEditVariable ) );
+ PyModule_AddObject( mod, "BadRequiredStrength", newref( BadRequiredStrength ) );
+
+#if PY_MAJOR_VERSION >= 3
+ return mod;
+#endif
+}
diff --git a/contrib/python/kiwisolver/py2/py/pythonhelpers.h b/contrib/python/kiwisolver/py2/py/pythonhelpers.h
new file mode 100644
index 00000000000..a9e0db634d7
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/py/pythonhelpers.h
@@ -0,0 +1,771 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <Python.h>
+#include <structmember.h>
+#include <string>
+
+#if PY_MAJOR_VERSION >= 3
+#define FROM_STRING PyUnicode_FromString
+#define INITERROR return NULL
+#define MOD_INIT_FUNC(name) PyMODINIT_FUNC PyInit_##name(void)
+#else
+#define FROM_STRING PyString_FromString
+#define INITERROR return
+#define MOD_INIT_FUNC(name) PyMODINIT_FUNC init##name(void)
+#endif
+
+#ifndef Py_RETURN_NOTIMPLEMENTED
+#define Py_RETURN_NOTIMPLEMENTED \
+ return Py_INCREF(Py_NotImplemented), Py_NotImplemented
+#endif
+
+#define pyobject_cast( o ) ( reinterpret_cast<PyObject*>( o ) )
+#define pytype_cast( o ) ( reinterpret_cast<PyTypeObject*>( o ) )
+
+struct module_state {
+ PyObject *error;
+};
+
+
+namespace PythonHelpers
+{
+
+
+/*-----------------------------------------------------------------------------
+| Exception Handling
+|----------------------------------------------------------------------------*/
+inline PyObject*
+py_bad_internal_call( const char* message )
+{
+ PyErr_SetString( PyExc_SystemError, message );
+ return 0;
+}
+
+
+inline PyObject*
+py_type_fail( const char* message )
+{
+ PyErr_SetString( PyExc_TypeError, message );
+ return 0;
+}
+
+
+inline PyObject*
+py_expected_type_fail( PyObject* pyobj, const char* expected_type )
+{
+ PyErr_Format(
+ PyExc_TypeError,
+ "Expected object of type `%s`. Got object of type `%s` instead.",
+ expected_type, pyobj->ob_type->tp_name
+ );
+ return 0;
+}
+
+
+inline PyObject*
+py_value_fail( const char* message )
+{
+ PyErr_SetString( PyExc_ValueError, message );
+ return 0;
+}
+
+
+inline PyObject*
+py_runtime_fail( const char* message )
+{
+ PyErr_SetString( PyExc_RuntimeError, message );
+ return 0;
+}
+
+
+inline PyObject*
+py_attr_fail( const char* message )
+{
+ PyErr_SetString( PyExc_AttributeError, message );
+ return 0;
+}
+
+
+inline PyObject*
+py_no_attr_fail( PyObject* pyobj, const char* attr )
+{
+ PyErr_Format(
+ PyExc_AttributeError,
+ "'%s' object has no attribute '%s'",
+ pyobj->ob_type->tp_name, attr
+ );
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------------
+| Utilities
+|----------------------------------------------------------------------------*/
+inline PyObject*
+newref( PyObject* pyobj )
+{
+ Py_INCREF( pyobj );
+ return pyobj;
+}
+
+
+inline PyObject*
+xnewref( PyObject* pyobj )
+{
+ Py_XINCREF( pyobj );
+ return pyobj;
+}
+
+
+inline PyObject*
+py_bool( bool val )
+{
+ return newref( val ? Py_True : Py_False );
+}
+
+
+inline PyCFunction
+lookup_method( PyTypeObject* type, const char* name )
+{
+ PyMethodDef* method = type->tp_methods;
+ for( ; method->ml_name != 0; ++method )
+ {
+ if( strcmp( method->ml_name, name ) == 0 )
+ return method->ml_meth;
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------------
+| Object Ptr
+|----------------------------------------------------------------------------*/
+class PyObjectPtr {
+
+public:
+
+ PyObjectPtr() : m_pyobj( 0 ) {}
+
+ PyObjectPtr( const PyObjectPtr& objptr ) :
+ m_pyobj( PythonHelpers::xnewref( objptr.m_pyobj ) ) {}
+
+ PyObjectPtr( PyObject* pyobj ) : m_pyobj( pyobj ) {}
+
+ ~PyObjectPtr()
+ {
+ xdecref_release();
+ }
+
+ PyObject* get() const
+ {
+ return m_pyobj;
+ }
+
+ void set( PyObject* pyobj )
+ {
+ PyObject* old = m_pyobj;
+ m_pyobj = pyobj;
+ Py_XDECREF( old );
+ }
+
+ PyObject* release()
+ {
+ PyObject* pyobj = m_pyobj;
+ m_pyobj = 0;
+ return pyobj;
+ }
+
+ PyObject* decref_release()
+ {
+ PyObject* pyobj = m_pyobj;
+ m_pyobj = 0;
+ Py_DECREF( pyobj );
+ return pyobj;
+ }
+
+ PyObject* xdecref_release()
+ {
+ PyObject* pyobj = m_pyobj;
+ m_pyobj = 0;
+ Py_XDECREF( pyobj );
+ return pyobj;
+ }
+
+ PyObject* incref_release()
+ {
+ PyObject* pyobj = m_pyobj;
+ m_pyobj = 0;
+ Py_INCREF( pyobj );
+ return pyobj;
+ }
+
+ PyObject* xincref_release()
+ {
+ PyObject* pyobj = m_pyobj;
+ m_pyobj = 0;
+ Py_XINCREF( pyobj );
+ return pyobj;
+ }
+
+ void incref() const
+ {
+ Py_INCREF( m_pyobj );
+ }
+
+ void decref() const
+ {
+ Py_DECREF( m_pyobj );
+ }
+
+ void xincref() const
+ {
+ Py_XINCREF( m_pyobj );
+ }
+
+ void xdecref() const
+ {
+ Py_XDECREF( m_pyobj );
+ }
+
+ PyObject* newref() const
+ {
+ Py_INCREF( m_pyobj );
+ return m_pyobj;
+ }
+
+ PyObject* xnewref() const
+ {
+ Py_XINCREF( m_pyobj );
+ return m_pyobj;
+ }
+
+ size_t refcount() const
+ {
+ if( m_pyobj )
+ return m_pyobj->ob_refcnt;
+ return 0;
+ }
+
+ bool is_true( bool clear_err=true ) const
+ {
+ int truth = PyObject_IsTrue( m_pyobj );
+ if( truth == 1 )
+ return true;
+ if( truth == 0 )
+ return false;
+ if( clear_err )
+ PyErr_Clear();
+ return false;
+ }
+
+ bool is_None() const
+ {
+ return m_pyobj == Py_None;
+ }
+
+ bool is_True() const
+ {
+ return m_pyobj == Py_True;
+ }
+
+ bool is_False() const
+ {
+ return m_pyobj == Py_False;
+ }
+
+ bool load_dict( PyObjectPtr& out, bool forcecreate=false )
+ {
+ PyObject** dict = _PyObject_GetDictPtr( m_pyobj );
+ if( !dict )
+ return false;
+ if( forcecreate && !*dict )
+ *dict = PyDict_New();
+ out = PythonHelpers::xnewref( *dict );
+ return true;
+ }
+
+ bool richcompare( PyObject* other, int opid, bool clear_err=true )
+ {
+ int r = PyObject_RichCompareBool( m_pyobj, other, opid );
+ if( r == 1 )
+ return true;
+ if( r == 0 )
+ return false;
+ if( clear_err && PyErr_Occurred() )
+ PyErr_Clear();
+ return false;
+ }
+
+ bool richcompare( PyObjectPtr& other, int opid, bool clear_err=true )
+ {
+ return richcompare( other.m_pyobj, opid, clear_err );
+ }
+
+ bool hasattr( PyObject* attr )
+ {
+ return PyObject_HasAttr( m_pyobj, attr ) == 1;
+ }
+
+ bool hasattr( PyObjectPtr& attr )
+ {
+ return PyObject_HasAttr( m_pyobj, attr.get() ) == 1;
+ }
+
+ bool hasattr( const char* attr )
+ {
+ return PyObject_HasAttrString( m_pyobj, attr ) == 1;
+ }
+
+ bool hasattr( std::string& attr )
+ {
+ return hasattr( attr.c_str() );
+ }
+
+ PyObjectPtr getattr( PyObject* attr )
+ {
+ return PyObjectPtr( PyObject_GetAttr( m_pyobj, attr ) );
+ }
+
+ PyObjectPtr getattr( PyObjectPtr& attr )
+ {
+ return PyObjectPtr( PyObject_GetAttr( m_pyobj, attr.get() ) );
+ }
+
+ PyObjectPtr getattr( const char* attr )
+ {
+ return PyObjectPtr( PyObject_GetAttrString( m_pyobj, attr ) );
+ }
+
+ PyObjectPtr getattr( std::string& attr )
+ {
+ return getattr( attr.c_str() );
+ }
+
+ bool setattr( PyObject* attr, PyObject* value )
+ {
+ return PyObject_SetAttr( m_pyobj, attr, value ) == 0;
+ }
+
+ bool setattr( PyObjectPtr& attr, PyObjectPtr& value )
+ {
+ return PyObject_SetAttr( m_pyobj, attr.get(), value.get() ) == 0;
+ }
+
+ PyObjectPtr operator()( PyObjectPtr& args ) const
+ {
+ return PyObjectPtr( PyObject_Call( m_pyobj, args.get(), 0 ) );
+ }
+
+ PyObjectPtr operator()( PyObjectPtr& args, PyObjectPtr& kwargs ) const
+ {
+ return PyObjectPtr( PyObject_Call( m_pyobj, args.get(), kwargs.get() ) );
+ }
+
+ operator void*() const
+ {
+ return static_cast<void*>( m_pyobj );
+ }
+
+ PyObjectPtr& operator=( const PyObjectPtr& rhs )
+ {
+ PyObject* old = m_pyobj;
+ m_pyobj = rhs.m_pyobj;
+ Py_XINCREF( m_pyobj );
+ Py_XDECREF( old );
+ return *this;
+ }
+
+ PyObjectPtr& operator=( PyObject* rhs )
+ {
+ PyObject* old = m_pyobj;
+ m_pyobj = rhs;
+ Py_XDECREF( old );
+ return *this;
+ }
+
+protected:
+
+ PyObject* m_pyobj;
+
+};
+
+
+inline bool
+operator!=( const PyObjectPtr& lhs, const PyObjectPtr& rhs )
+{
+ return lhs.get() != rhs.get();
+}
+
+
+inline bool
+operator!=( const PyObject* lhs, const PyObjectPtr& rhs )
+{
+ return lhs != rhs.get();
+}
+
+
+inline bool
+operator!=( const PyObjectPtr& lhs, const PyObject* rhs )
+{
+ return lhs.get() != rhs;
+}
+
+
+inline bool
+operator==( const PyObjectPtr& lhs, const PyObjectPtr& rhs )
+{
+ return lhs.get() == rhs.get();
+}
+
+
+inline bool
+operator==( const PyObject* lhs, const PyObjectPtr& rhs )
+{
+ return lhs == rhs.get();
+}
+
+
+inline bool
+operator==( const PyObjectPtr& lhs, const PyObject* rhs )
+{
+ return lhs.get() == rhs;
+}
+
+
+/*-----------------------------------------------------------------------------
+| Tuple Ptr
+|----------------------------------------------------------------------------*/
+class PyTuplePtr : public PyObjectPtr {
+
+public:
+
+ PyTuplePtr() : PyObjectPtr() {}
+
+ PyTuplePtr( const PyObjectPtr& objptr ) : PyObjectPtr( objptr ) {}
+
+ PyTuplePtr( PyObject* pytuple ) : PyObjectPtr( pytuple ) {}
+
+ bool check()
+ {
+ return PyTuple_Check( m_pyobj );
+ }
+
+ bool check_exact()
+ {
+ return PyTuple_CheckExact( m_pyobj );
+ }
+
+ Py_ssize_t size() const
+ {
+ return PyTuple_GET_SIZE( m_pyobj );
+ }
+
+ PyObjectPtr get_item( Py_ssize_t index ) const
+ {
+ return PyObjectPtr( PythonHelpers::newref( PyTuple_GET_ITEM( m_pyobj, index ) ) );
+ }
+
+ void set_item( Py_ssize_t index, PyObject* pyobj )
+ {
+ PyObject* old_item = PyTuple_GET_ITEM( m_pyobj, index );
+ PyTuple_SET_ITEM( m_pyobj, index, pyobj );
+ Py_XDECREF( old_item );
+ }
+
+ void set_item( Py_ssize_t index, PyObjectPtr& item )
+ {
+ PyObject* old_item = PyTuple_GET_ITEM( m_pyobj, index );
+ PyTuple_SET_ITEM( m_pyobj, index, item.get() );
+ Py_XINCREF( item.get() );
+ Py_XDECREF( old_item );
+ }
+
+ // pyobj must not be null, only use to fill a new empty tuple
+ void initialize( Py_ssize_t index, PyObject* pyobj )
+ {
+ PyTuple_SET_ITEM( m_pyobj, index, pyobj );
+ }
+
+ // ptr must not be empty, only use to fill a new empty tuple
+ void initialize( Py_ssize_t index, PyObjectPtr& item )
+ {
+ PyTuple_SET_ITEM( m_pyobj, index, item.get() );
+ Py_INCREF( item.get() );
+ }
+
+};
+
+
+/*-----------------------------------------------------------------------------
+| List Ptr
+|----------------------------------------------------------------------------*/
+class PyListPtr : public PyObjectPtr {
+
+public:
+
+ PyListPtr() : PyObjectPtr() {}
+
+ PyListPtr( const PyObjectPtr& objptr ) : PyObjectPtr( objptr ) {}
+
+ PyListPtr( PyObject* pylist ) : PyObjectPtr( pylist ) {}
+
+ bool check() const
+ {
+ return PyList_Check( m_pyobj );
+ }
+
+ bool check_exact() const
+ {
+ return PyList_CheckExact( m_pyobj );
+ }
+
+ Py_ssize_t size() const
+ {
+ return PyList_GET_SIZE( m_pyobj );
+ }
+
+ PyObject* borrow_item( Py_ssize_t index ) const
+ {
+ return PyList_GET_ITEM( m_pyobj, index );
+ }
+
+ PyObjectPtr get_item( Py_ssize_t index ) const
+ {
+ return PyObjectPtr( PythonHelpers::newref( PyList_GET_ITEM( m_pyobj, index ) ) );
+ }
+
+ void set_item( Py_ssize_t index, PyObject* pyobj ) const
+ {
+ PyObject* old_item = PyList_GET_ITEM( m_pyobj, index );
+ PyList_SET_ITEM( m_pyobj, index, pyobj );
+ Py_XDECREF( old_item );
+ }
+
+ void set_item( Py_ssize_t index, PyObjectPtr& item ) const
+ {
+ PyObject* old_item = PyList_GET_ITEM( m_pyobj, index );
+ PyList_SET_ITEM( m_pyobj, index, item.get() );
+ Py_XINCREF( item.get() );
+ Py_XDECREF( old_item );
+ }
+
+ bool del_item( Py_ssize_t index ) const
+ {
+ if( PySequence_DelItem( m_pyobj, index ) == -1 )
+ return false;
+ return true;
+ }
+
+ bool append( PyObjectPtr& pyobj ) const
+ {
+ if( PyList_Append( m_pyobj, pyobj.get() ) == 0 )
+ return true;
+ return false;
+ }
+
+ Py_ssize_t index( PyObjectPtr& item ) const
+ {
+ Py_ssize_t maxidx = size();
+ for( Py_ssize_t idx = 0; idx < maxidx; idx++ )
+ {
+ PyObjectPtr other( get_item( idx ) );
+ if( item.richcompare( other, Py_EQ ) )
+ return idx;
+ }
+ return -1;
+ }
+
+};
+
+
+/*-----------------------------------------------------------------------------
+| Dict Ptr
+|----------------------------------------------------------------------------*/
+class PyDictPtr : public PyObjectPtr {
+
+public:
+
+ PyDictPtr() : PyObjectPtr() {}
+
+ PyDictPtr( const PyObjectPtr& objptr ) : PyObjectPtr( objptr ) {}
+
+ PyDictPtr( PyObject* pydict ) : PyObjectPtr( pydict ) {}
+
+ bool check()
+ {
+ return PyDict_Check( m_pyobj );
+ }
+
+ bool check_exact()
+ {
+ return PyDict_CheckExact( m_pyobj );
+ }
+
+ Py_ssize_t size() const
+ {
+ return PyDict_Size( m_pyobj );
+ }
+
+ PyObjectPtr get_item( PyObject* key ) const
+ {
+ return PyObjectPtr( PythonHelpers::xnewref( PyDict_GetItem( m_pyobj, key ) ) ) ;
+ }
+
+ PyObjectPtr get_item( PyObjectPtr& key ) const
+ {
+ return PyObjectPtr( PythonHelpers::xnewref( PyDict_GetItem( m_pyobj, key.get() ) ) );
+ }
+
+ PyObjectPtr get_item( const char* key ) const
+ {
+ return PyObjectPtr( PythonHelpers::xnewref( PyDict_GetItemString( m_pyobj, key ) ) );
+ }
+
+ PyObjectPtr get_item( std::string& key ) const
+ {
+ return get_item( key.c_str() );
+ }
+
+ bool set_item( PyObject* key, PyObject* value ) const
+ {
+ if( PyDict_SetItem( m_pyobj, key, value ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool set_item( PyObject* key, PyObjectPtr& value ) const
+ {
+ if( PyDict_SetItem( m_pyobj, key, value.get() ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool set_item( PyObjectPtr& key, PyObject* value ) const
+ {
+ if( PyDict_SetItem( m_pyobj, key.get(), value ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool set_item( PyObjectPtr& key, PyObjectPtr& value ) const
+ {
+ if( PyDict_SetItem( m_pyobj, key.get(), value.get() ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool set_item( const char* key, PyObjectPtr& value ) const
+ {
+ if( PyDict_SetItemString( m_pyobj, key, value.get() ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool set_item( const char* key, PyObject* value ) const
+ {
+ if( PyDict_SetItemString( m_pyobj, key, value ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool set_item( std::string& key, PyObjectPtr& value ) const
+ {
+ return set_item( key.c_str(), value );
+ }
+
+ bool del_item( PyObjectPtr& key ) const
+ {
+ if( PyDict_DelItem( m_pyobj, key.get() ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool del_item( const char* key ) const
+ {
+ if( PyDict_DelItemString( m_pyobj, key ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool del_item( std::string& key ) const
+ {
+ return del_item( key.c_str() );
+ }
+
+};
+
+
+/*-----------------------------------------------------------------------------
+| Method Ptr
+|----------------------------------------------------------------------------*/
+class PyMethodPtr : public PyObjectPtr {
+
+public:
+
+ PyMethodPtr() : PyObjectPtr() {}
+
+ PyMethodPtr( const PyObjectPtr& objptr ) : PyObjectPtr( objptr ) {}
+
+ PyMethodPtr( PyObject* pymethod ) : PyObjectPtr( pymethod ) {}
+
+ bool check()
+ {
+ return PyMethod_Check( m_pyobj );
+ }
+
+ PyObjectPtr get_self() const
+ {
+ return PyObjectPtr( PythonHelpers::xnewref( PyMethod_GET_SELF( m_pyobj ) ) );
+ }
+
+ PyObjectPtr get_function() const
+ {
+ return PyObjectPtr( PythonHelpers::xnewref( PyMethod_GET_FUNCTION( m_pyobj ) ) );
+ }
+
+#if PY_MAJOR_VERSION < 3
+ PyObjectPtr get_class() const
+ {
+ return PyObjectPtr( PythonHelpers::xnewref( PyMethod_GET_CLASS( m_pyobj ) ) );
+ }
+#endif
+};
+
+
+/*-----------------------------------------------------------------------------
+| Weakref Ptr
+|----------------------------------------------------------------------------*/
+class PyWeakrefPtr : public PyObjectPtr {
+
+public:
+
+ PyWeakrefPtr() : PyObjectPtr() {}
+
+ PyWeakrefPtr( const PyObjectPtr& objptr ) : PyObjectPtr( objptr ) {}
+
+ PyWeakrefPtr( PyObject* pyweakref ) : PyObjectPtr( pyweakref ) {}
+
+ bool check()
+ {
+ return PyWeakref_CheckRef( m_pyobj );
+ }
+
+ bool check_exact()
+ {
+ return PyWeakref_CheckRefExact( m_pyobj );
+ }
+
+ PyObjectPtr get_object() const
+ {
+ return PyObjectPtr( PythonHelpers::newref( PyWeakref_GET_OBJECT( m_pyobj ) ) );
+ }
+
+};
+
+} // namespace PythonHelpers
diff --git a/contrib/python/kiwisolver/py2/py/solver.cpp b/contrib/python/kiwisolver/py2/py/solver.cpp
new file mode 100644
index 00000000000..7a2ef23ca33
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/py/solver.cpp
@@ -0,0 +1,333 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <Python.h>
+#include <kiwi/kiwi.h>
+#include "pythonhelpers.h"
+#include "types.h"
+#include "util.h"
+
+
+using namespace PythonHelpers;
+
+
+static PyObject*
+Solver_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
+{
+ if( PyTuple_GET_SIZE( args ) != 0 || ( kwargs && PyDict_Size( kwargs ) != 0 ) )
+ return py_type_fail( "Solver.__new__ takes no arguments" );
+ PyObject* pysolver = PyType_GenericNew( type, args, kwargs );
+ if( !pysolver )
+ return 0;
+ Solver* self = reinterpret_cast<Solver*>( pysolver );
+ new( &self->solver ) kiwi::Solver();
+ return pysolver;
+}
+
+
+static void
+Solver_dealloc( Solver* self )
+{
+ self->solver.~Solver();
+ Py_TYPE( self )->tp_free( pyobject_cast( self ) );
+}
+
+
+static PyObject*
+Solver_addConstraint( Solver* self, PyObject* other )
+{
+ if( !Constraint::TypeCheck( other ) )
+ return py_expected_type_fail( other, "Constraint" );
+ Constraint* cn = reinterpret_cast<Constraint*>( other );
+ try
+ {
+ self->solver.addConstraint( cn->constraint );
+ }
+ catch( const kiwi::DuplicateConstraint& )
+ {
+ PyErr_SetObject( DuplicateConstraint, other );
+ return 0;
+ }
+ catch( const kiwi::UnsatisfiableConstraint& )
+ {
+ PyErr_SetObject( UnsatisfiableConstraint, other );
+ return 0;
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_removeConstraint( Solver* self, PyObject* other )
+{
+ if( !Constraint::TypeCheck( other ) )
+ return py_expected_type_fail( other, "Constraint" );
+ Constraint* cn = reinterpret_cast<Constraint*>( other );
+ try
+ {
+ self->solver.removeConstraint( cn->constraint );
+ }
+ catch( const kiwi::UnknownConstraint& )
+ {
+ PyErr_SetObject( UnknownConstraint, other );
+ return 0;
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_hasConstraint( Solver* self, PyObject* other )
+{
+ if( !Constraint::TypeCheck( other ) )
+ return py_expected_type_fail( other, "Constraint" );
+ Constraint* cn = reinterpret_cast<Constraint*>( other );
+ return newref( self->solver.hasConstraint( cn->constraint ) ? Py_True : Py_False );
+}
+
+
+static PyObject*
+Solver_addEditVariable( Solver* self, PyObject* args )
+{
+ PyObject* pyvar;
+ PyObject* pystrength;
+ if( !PyArg_ParseTuple( args, "OO", &pyvar, &pystrength ) )
+ return 0;
+ if( !Variable::TypeCheck( pyvar ) )
+ return py_expected_type_fail( pyvar, "Variable" );
+ double strength;
+ if( !convert_to_strength( pystrength, strength ) )
+ return 0;
+ Variable* var = reinterpret_cast<Variable*>( pyvar );
+ try
+ {
+ self->solver.addEditVariable( var->variable, strength );
+ }
+ catch( const kiwi::DuplicateEditVariable& )
+ {
+ PyErr_SetObject( DuplicateEditVariable, pyvar );
+ return 0;
+ }
+ catch( const kiwi::BadRequiredStrength& e )
+ {
+ PyErr_SetString( BadRequiredStrength, e.what() );
+ return 0;
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_removeEditVariable( Solver* self, PyObject* other )
+{
+ if( !Variable::TypeCheck( other ) )
+ return py_expected_type_fail( other, "Variable" );
+ Variable* var = reinterpret_cast<Variable*>( other );
+ try
+ {
+ self->solver.removeEditVariable( var->variable );
+ }
+ catch( const kiwi::UnknownEditVariable& )
+ {
+ PyErr_SetObject( UnknownEditVariable, other );
+ return 0;
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_hasEditVariable( Solver* self, PyObject* other )
+{
+ if( !Variable::TypeCheck( other ) )
+ return py_expected_type_fail( other, "Variable" );
+ Variable* var = reinterpret_cast<Variable*>( other );
+ return newref( self->solver.hasEditVariable( var->variable ) ? Py_True : Py_False );
+}
+
+
+static PyObject*
+Solver_suggestValue( Solver* self, PyObject* args )
+{
+ PyObject* pyvar;
+ PyObject* pyvalue;
+ if( !PyArg_ParseTuple( args, "OO", &pyvar, &pyvalue ) )
+ return 0;
+ if( !Variable::TypeCheck( pyvar ) )
+ return py_expected_type_fail( pyvar, "Variable" );
+ double value;
+ if( !convert_to_double( pyvalue, value ) )
+ return 0;
+ Variable* var = reinterpret_cast<Variable*>( pyvar );
+ try
+ {
+ self->solver.suggestValue( var->variable, value );
+ }
+ catch( const kiwi::UnknownEditVariable& )
+ {
+ PyErr_SetObject( UnknownEditVariable, pyvar );
+ return 0;
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_updateVariables( Solver* self )
+{
+ self->solver.updateVariables();
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_reset( Solver* self )
+{
+ self->solver.reset();
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_dump( Solver* self )
+{
+ PyObjectPtr dump_str( PyUnicode_FromString( self->solver.dumps().c_str() ) );
+ PyObject_Print( dump_str.get(), stdout, 0 );
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+Solver_dumps( Solver* self )
+{
+ return PyUnicode_FromString( self->solver.dumps().c_str() );
+}
+
+static PyMethodDef
+Solver_methods[] = {
+ { "addConstraint", ( PyCFunction )Solver_addConstraint, METH_O,
+ "Add a constraint to the solver." },
+ { "removeConstraint", ( PyCFunction )Solver_removeConstraint, METH_O,
+ "Remove a constraint from the solver." },
+ { "hasConstraint", ( PyCFunction )Solver_hasConstraint, METH_O,
+ "Check whether the solver contains a constraint." },
+ { "addEditVariable", ( PyCFunction )Solver_addEditVariable, METH_VARARGS,
+ "Add an edit variable to the solver." },
+ { "removeEditVariable", ( PyCFunction )Solver_removeEditVariable, METH_O,
+ "Remove an edit variable from the solver." },
+ { "hasEditVariable", ( PyCFunction )Solver_hasEditVariable, METH_O,
+ "Check whether the solver contains an edit variable." },
+ { "suggestValue", ( PyCFunction )Solver_suggestValue, METH_VARARGS,
+ "Suggest a desired value for an edit variable." },
+ { "updateVariables", ( PyCFunction )Solver_updateVariables, METH_NOARGS,
+ "Update the values of the solver variables." },
+ { "reset", ( PyCFunction )Solver_reset, METH_NOARGS,
+ "Reset the solver to the initial empty starting condition." },
+ { "dump", ( PyCFunction )Solver_dump, METH_NOARGS,
+ "Dump a representation of the solver internals to stdout." },
+ { "dumps", ( PyCFunction )Solver_dumps, METH_NOARGS,
+ "Dump a representation of the solver internals to a string." },
+ { 0 } // sentinel
+};
+
+
+PyTypeObject Solver_Type = {
+ PyVarObject_HEAD_INIT( &PyType_Type, 0 )
+ "kiwisolver.Solver", /* tp_name */
+ sizeof( Solver ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Solver_dealloc, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03050000
+ ( PyAsyncMethods* )0, /* tp_as_async */
+#elif PY_VERSION_HEX >= 0x03000000
+ ( void* ) 0, /* tp_reserved */
+#else
+ ( cmpfunc )0, /* tp_compare */
+#endif
+ (reprfunc)0, /* tp_repr */
+ (PyNumberMethods*)0, /* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
+ 0, /* Documentation string */
+ (traverseproc)0, /* tp_traverse */
+ (inquiry)0, /* tp_clear */
+ (richcmpfunc)0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)Solver_methods, /* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)Solver_new, /* tp_new */
+ (freefunc)PyObject_Del, /* tp_free */
+ (inquiry)0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ (destructor)0 /* tp_del */
+};
+
+
+PyObject* DuplicateConstraint;
+
+PyObject* UnsatisfiableConstraint;
+
+PyObject* UnknownConstraint;
+
+PyObject* DuplicateEditVariable;
+
+PyObject* UnknownEditVariable;
+
+PyObject* BadRequiredStrength;
+
+
+int import_solver()
+{
+ DuplicateConstraint = PyErr_NewException(
+ const_cast<char*>( "kiwisolver.DuplicateConstraint" ), 0, 0 );
+ if( !DuplicateConstraint )
+ return -1;
+ UnsatisfiableConstraint = PyErr_NewException(
+ const_cast<char*>( "kiwisolver.UnsatisfiableConstraint" ), 0, 0 );
+ if( !UnsatisfiableConstraint )
+ return -1;
+ UnknownConstraint = PyErr_NewException(
+ const_cast<char*>( "kiwisolver.UnknownConstraint" ), 0, 0 );
+ if( !UnknownConstraint )
+ return -1;
+ DuplicateEditVariable = PyErr_NewException(
+ const_cast<char*>( "kiwisolver.DuplicateEditVariable" ), 0, 0 );
+ if( !DuplicateEditVariable )
+ return -1;
+ UnknownEditVariable = PyErr_NewException(
+ const_cast<char*>( "kiwisolver.UnknownEditVariable" ), 0, 0 );
+ if( !UnknownEditVariable )
+ return -1;
+ BadRequiredStrength = PyErr_NewException(
+ const_cast<char*>( "kiwisolver.BadRequiredStrength" ), 0, 0 );
+ if( !BadRequiredStrength )
+ return -1;
+ return PyType_Ready( &Solver_Type );
+}
diff --git a/contrib/python/kiwisolver/py2/py/strength.cpp b/contrib/python/kiwisolver/py2/py/strength.cpp
new file mode 100644
index 00000000000..df1552d1947
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/py/strength.cpp
@@ -0,0 +1,162 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <Python.h>
+#include <kiwi/kiwi.h>
+#include "pythonhelpers.h"
+#include "util.h"
+
+
+using namespace PythonHelpers;
+
+
+struct strength
+{
+ PyObject_HEAD;
+};
+
+
+static void
+strength_dealloc( PyObject* self )
+{
+ Py_TYPE( self )->tp_free( self );
+}
+
+
+static PyObject*
+strength_weak( strength* self )
+{
+ return PyFloat_FromDouble( kiwi::strength::weak );
+}
+
+
+static PyObject*
+strength_medium( strength* self )
+{
+ return PyFloat_FromDouble( kiwi::strength::medium );
+}
+
+
+static PyObject*
+strength_strong( strength* self )
+{
+ return PyFloat_FromDouble( kiwi::strength::strong );
+}
+
+
+static PyObject*
+strength_required( strength* self )
+{
+ return PyFloat_FromDouble( kiwi::strength::required );
+}
+
+
+static PyObject*
+strength_create( strength* self, PyObject* args )
+{
+ PyObject* pya;
+ PyObject* pyb;
+ PyObject* pyc;
+ PyObject* pyw = 0;
+ if( !PyArg_ParseTuple( args, "OOO|O", &pya, &pyb, &pyc, &pyw ) )
+ return 0;
+ double a, b, c;
+ double w = 1.0;
+ if( !convert_to_double( pya, a ) )
+ return 0;
+ if( !convert_to_double( pyb, b ) )
+ return 0;
+ if( !convert_to_double( pyc, c ) )
+ return 0;
+ if( pyw && !convert_to_double( pyw, w ) )
+ return 0;
+ return PyFloat_FromDouble( kiwi::strength::create( a, b, c, w ) );
+}
+
+
+static PyGetSetDef
+strength_getset[] = {
+ { "weak", ( getter )strength_weak, 0,
+ "The predefined weak strength." },
+ { "medium", ( getter )strength_medium, 0,
+ "The predefined medium strength." },
+ { "strong", ( getter )strength_strong, 0,
+ "The predefined strong strength." },
+ { "required", ( getter )strength_required, 0,
+ "The predefined required strength." },
+ { 0 } // sentinel
+};
+
+
+static PyMethodDef
+strength_methods[] = {
+ { "create", ( PyCFunction )strength_create, METH_VARARGS,
+ "Create a strength from constituent values and optional weight." },
+ { 0 } // sentinel
+};
+
+
+PyTypeObject strength_Type = {
+ PyVarObject_HEAD_INIT( &PyType_Type, 0 )
+ "kiwisolver.strength", /* tp_name */
+ sizeof( strength ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)strength_dealloc, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03050000
+ ( PyAsyncMethods* )0, /* tp_as_async */
+#elif PY_VERSION_HEX >= 0x03000000
+ ( void* ) 0, /* tp_reserved */
+#else
+ ( cmpfunc )0, /* tp_compare */
+#endif
+ (reprfunc)0, /* tp_repr */
+ (PyNumberMethods*)0, /* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* Documentation string */
+ (traverseproc)0, /* tp_traverse */
+ (inquiry)0, /* tp_clear */
+ (richcmpfunc)0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)strength_methods, /* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ strength_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)0, /* tp_new */
+ (freefunc)PyObject_Del, /* tp_free */
+ (inquiry)0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ (destructor)0 /* tp_del */
+};
+
+
+int import_strength()
+{
+ return PyType_Ready( &strength_Type );
+}
diff --git a/contrib/python/kiwisolver/py2/py/symbolics.h b/contrib/python/kiwisolver/py2/py/symbolics.h
new file mode 100644
index 00000000000..ac575537403
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/py/symbolics.h
@@ -0,0 +1,620 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <Python.h>
+#include "pythonhelpers.h"
+#include "types.h"
+#include "util.h"
+
+
+template<typename Op, typename T>
+struct UnaryInvoke
+{
+ PyObject* operator()( PyObject* value )
+ {
+ return Op()( reinterpret_cast<T*>( value ) );
+ }
+};
+
+
+template<typename Op, typename T>
+struct BinaryInvoke
+{
+ PyObject* operator()( PyObject* first, PyObject* second )
+ {
+ if( T::TypeCheck( first ) )
+ return invoke<Normal>( reinterpret_cast<T*>( first ), second );
+ return invoke<Reverse>( reinterpret_cast<T*>( second ), first );
+ }
+
+ struct Normal
+ {
+ template<typename U>
+ PyObject* operator()( T* primary, U secondary )
+ {
+ return Op()( primary, secondary );
+ }
+ };
+
+ struct Reverse
+ {
+ template<typename U>
+ PyObject* operator()( T* primary, U secondary )
+ {
+ return Op()( secondary, primary );
+ }
+ };
+
+ template<typename Invk>
+ PyObject* invoke( T* primary, PyObject* secondary )
+ {
+ if( Expression::TypeCheck( secondary ) )
+ return Invk()( primary, reinterpret_cast<Expression*>( secondary ) );
+ if( Term::TypeCheck( secondary ) )
+ return Invk()( primary, reinterpret_cast<Term*>( secondary ) );
+ if( Variable::TypeCheck( secondary ) )
+ return Invk()( primary, reinterpret_cast<Variable*>( secondary ) );
+ if( PyFloat_Check( secondary ) )
+ return Invk()( primary, PyFloat_AS_DOUBLE( secondary ) );
+#if PY_MAJOR_VERSION < 3
+ if( PyInt_Check( secondary ) )
+ return Invk()( primary, double( PyInt_AS_LONG( secondary ) ) );
+#endif
+ if( PyLong_Check( secondary ) )
+ {
+ double v = PyLong_AsDouble( secondary );
+ if( v == -1 && PyErr_Occurred() )
+ return 0;
+ return Invk()( primary, v );
+ }
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+};
+
+
+struct BinaryMul
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+};
+
+
+template<> inline
+PyObject* BinaryMul::operator()( Variable* first, double second )
+{
+ PyObject* pyterm = PyType_GenericNew( &Term_Type, 0, 0 );
+ if( !pyterm )
+ return 0;
+ Term* term = reinterpret_cast<Term*>( pyterm );
+ term->variable = PythonHelpers::newref( pyobject_cast( first ) );
+ term->coefficient = second;
+ return pyterm;
+}
+
+
+template<> inline
+PyObject* BinaryMul::operator()( Term* first, double second )
+{
+ PyObject* pyterm = PyType_GenericNew( &Term_Type, 0, 0 );
+ if( !pyterm )
+ return 0;
+ Term* term = reinterpret_cast<Term*>( pyterm );
+ term->variable = PythonHelpers::newref( first->variable );
+ term->coefficient = first->coefficient * second;
+ return pyterm;
+}
+
+
+template<> inline
+PyObject* BinaryMul::operator()( Expression* first, double second )
+{
+ using namespace PythonHelpers;
+ PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
+ if( !pyexpr )
+ return 0;
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
+ PyObjectPtr terms( PyTuple_New( PyTuple_GET_SIZE( first->terms ) ) );
+ if( !terms )
+ return 0;
+ Py_ssize_t end = PyTuple_GET_SIZE( first->terms );
+ for( Py_ssize_t i = 0; i < end; ++i ) // memset 0 for safe error return
+ PyTuple_SET_ITEM( terms.get(), i, 0 );
+ for( Py_ssize_t i = 0; i < end; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( first->terms, i );
+ PyObject* term = BinaryMul()( reinterpret_cast<Term*>( item ), second );
+ if( !term )
+ return 0;
+ PyTuple_SET_ITEM( terms.get(), i, term );
+ }
+ expr->terms = terms.release();
+ expr->constant = first->constant * second;
+ return pyexpr.release();
+}
+
+
+template<> inline
+PyObject* BinaryMul::operator()( double first, Variable* second )
+{
+ return operator()( second, first );
+}
+
+
+template<> inline
+PyObject* BinaryMul::operator()( double first, Term* second )
+{
+ return operator()( second, first );
+}
+
+
+template<> inline
+PyObject* BinaryMul::operator()( double first, Expression* second )
+{
+ return operator()( second, first );
+}
+
+
+struct BinaryDiv
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+};
+
+
+template<> inline
+PyObject* BinaryDiv::operator()( Variable* first, double second )
+{
+ if( second == 0.0 )
+ {
+ PyErr_SetString( PyExc_ZeroDivisionError, "float division by zero" );
+ return 0;
+ }
+ return BinaryMul()( first, 1.0 / second );
+}
+
+
+template<> inline
+PyObject* BinaryDiv::operator()( Term* first, double second )
+{
+ if( second == 0.0 )
+ {
+ PyErr_SetString( PyExc_ZeroDivisionError, "float division by zero" );
+ return 0;
+ }
+ return BinaryMul()( first, 1.0 / second );
+}
+
+
+template<> inline
+PyObject* BinaryDiv::operator()( Expression* first, double second )
+{
+ if( second == 0.0 )
+ {
+ PyErr_SetString( PyExc_ZeroDivisionError, "float division by zero" );
+ return 0;
+ }
+ return BinaryMul()( first, 1.0 / second );
+}
+
+
+struct UnaryNeg
+{
+ template<typename T>
+ PyObject* operator()( T value )
+ {
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+};
+
+
+template<> inline
+PyObject* UnaryNeg::operator()( Variable* value )
+{
+ return BinaryMul()( value, -1.0 );
+}
+
+
+template<> inline
+PyObject* UnaryNeg::operator()( Term* value )
+{
+ return BinaryMul()( value, -1.0 );
+}
+
+
+template<> inline
+PyObject* UnaryNeg::operator()( Expression* value )
+{
+ return BinaryMul()( value, -1.0 );
+}
+
+
+struct BinaryAdd
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+};
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Expression* first, Expression* second )
+{
+ PythonHelpers::PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
+ if( !pyexpr )
+ return 0;
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
+ expr->constant = first->constant + second->constant;
+ expr->terms = PySequence_Concat( first->terms, second->terms );
+ if( !expr->terms )
+ return 0;
+ return pyexpr.release();
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Expression* first, Term* second )
+{
+ using namespace PythonHelpers;
+ PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
+ if( !pyexpr )
+ return 0;
+ PyObject* terms = PyTuple_New( PyTuple_GET_SIZE( first->terms ) + 1 );
+ if( !terms )
+ return 0;
+ Py_ssize_t end = PyTuple_GET_SIZE( first->terms );
+ for( Py_ssize_t i = 0; i < end; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( first->terms, i );
+ PyTuple_SET_ITEM( terms, i, newref( item ) );
+ }
+ PyTuple_SET_ITEM( terms, end, newref( pyobject_cast( second ) ) );
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
+ expr->terms = terms;
+ expr->constant = first->constant;
+ return pyexpr.release();
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Expression* first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( BinaryMul()( second, 1.0 ) );
+ if( !temp )
+ return 0;
+ return operator()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Expression* first, double second )
+{
+ using namespace PythonHelpers;
+ PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
+ if( !pyexpr )
+ return 0;
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
+ expr->terms = newref( first->terms );
+ expr->constant = first->constant + second;
+ return pyexpr.release();
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Term* first, double second )
+{
+ PythonHelpers::PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
+ if( !pyexpr )
+ return 0;
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
+ expr->constant = second;
+ expr->terms = PyTuple_Pack( 1, first );
+ if( !expr->terms )
+ return 0;
+ return pyexpr.release();
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Term* first, Expression* second )
+{
+ return operator()( second, first );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Term* first, Term* second )
+{
+ PythonHelpers::PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
+ if( !pyexpr )
+ return 0;
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
+ expr->constant = 0.0;
+ expr->terms = PyTuple_Pack( 2, first, second );
+ if( !expr->terms )
+ return 0;
+ return pyexpr.release();
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Term* first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( BinaryMul()( second, 1.0 ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Variable* first, double second )
+{
+ PythonHelpers::PyObjectPtr temp( BinaryMul()( first, 1.0 ) );
+ if( !temp )
+ return 0;
+ return operator()( reinterpret_cast<Term*>( temp.get() ), second );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Variable* first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( BinaryMul()( first, 1.0 ) );
+ if( !temp )
+ return 0;
+ return operator()( reinterpret_cast<Term*>( temp.get() ), second );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Variable* first, Term* second )
+{
+ PythonHelpers::PyObjectPtr temp( BinaryMul()( first, 1.0 ) );
+ if( !temp )
+ return 0;
+ return operator()( reinterpret_cast<Term*>( temp.get() ), second );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Variable* first, Expression* second )
+{
+ PythonHelpers::PyObjectPtr temp( BinaryMul()( first, 1.0 ) );
+ if( !temp )
+ return 0;
+ return operator()( reinterpret_cast<Term*>( temp.get() ), second );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( double first, Variable* second )
+{
+ return operator()( second, first );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( double first, Term* second )
+{
+ return operator()( second, first );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( double first, Expression* second )
+{
+ return operator()( second, first );
+}
+
+
+struct BinarySub
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+};
+
+
+template<> inline
+PyObject* BinarySub::operator()( Variable* first, double second )
+{
+ return BinaryAdd()( first, -second );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Variable* first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Variable* first, Term* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Variable* first, Expression* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Expression*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Term* first, double second )
+{
+ return BinaryAdd()( first, -second );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Term* first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Term* first, Term* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Term* first, Expression* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Expression*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Expression* first, double second )
+{
+ return BinaryAdd()( first, -second );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Expression* first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Expression* first, Term* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Expression* first, Expression* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Expression*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( double first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( double first, Term* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( double first, Expression* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Expression*>( temp.get() ) );
+}
+
+
+template<typename T, typename U>
+PyObject* makecn( T first, U second, kiwi::RelationalOperator op )
+{
+ PythonHelpers::PyObjectPtr pyexpr( BinarySub()( first, second ) );
+ if( !pyexpr )
+ return 0;
+ PythonHelpers::PyObjectPtr pycn( PyType_GenericNew( &Constraint_Type, 0, 0 ) );
+ if( !pycn )
+ return 0;
+ Constraint* cn = reinterpret_cast<Constraint*>( pycn.get() );
+ cn->expression = reduce_expression( pyexpr.get() );
+ if( !cn->expression )
+ return 0;
+ kiwi::Expression expr( convert_to_kiwi_expression( cn->expression ) );
+ new( &cn->constraint ) kiwi::Constraint( expr, op, kiwi::strength::required );
+ return pycn.release();
+}
+
+
+struct CmpEQ
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ return makecn( first, second, kiwi::OP_EQ );
+ }
+};
+
+
+struct CmpLE
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ return makecn( first, second, kiwi::OP_LE );
+ }
+};
+
+
+struct CmpGE
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ return makecn( first, second, kiwi::OP_GE );
+ }
+};
diff --git a/contrib/python/kiwisolver/py2/py/term.cpp b/contrib/python/kiwisolver/py2/py/term.cpp
new file mode 100644
index 00000000000..4be64a1eeaf
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/py/term.cpp
@@ -0,0 +1,298 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <sstream>
+#include <Python.h>
+#include "pythonhelpers.h"
+#include "symbolics.h"
+#include "types.h"
+#include "util.h"
+
+
+using namespace PythonHelpers;
+
+
+static PyObject*
+Term_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
+{
+ static const char *kwlist[] = { "variable", "coefficient", 0 };
+ PyObject* pyvar;
+ PyObject* pycoeff = 0;
+ if( !PyArg_ParseTupleAndKeywords(
+ args, kwargs, "O|O:__new__", const_cast<char**>( kwlist ),
+ &pyvar, &pycoeff ) )
+ return 0;
+ if( !Variable::TypeCheck( pyvar ) )
+ return py_expected_type_fail( pyvar, "Variable" );
+ double coefficient = 1.0;
+ if( pycoeff && !convert_to_double( pycoeff, coefficient ) )
+ return 0;
+ PyObject* pyterm = PyType_GenericNew( type, args, kwargs );
+ if( !pyterm )
+ return 0;
+ Term* self = reinterpret_cast<Term*>( pyterm );
+ self->variable = newref( pyvar );
+ self->coefficient = coefficient;
+ return pyterm;
+}
+
+
+static void
+Term_clear( Term* self )
+{
+ Py_CLEAR( self->variable );
+}
+
+
+static int
+Term_traverse( Term* self, visitproc visit, void* arg )
+{
+ Py_VISIT( self->variable );
+ return 0;
+}
+
+
+static void
+Term_dealloc( Term* self )
+{
+ PyObject_GC_UnTrack( self );
+ Term_clear( self );
+ Py_TYPE( self )->tp_free( pyobject_cast( self ) );
+}
+
+
+static PyObject*
+Term_repr( Term* self )
+{
+ std::stringstream stream;
+ stream << self->coefficient << " * ";
+ stream << reinterpret_cast<Variable*>( self->variable )->variable.name();
+ return FROM_STRING( stream.str().c_str() );
+}
+
+
+static PyObject*
+Term_variable( Term* self )
+{
+ return newref( self->variable );
+}
+
+
+static PyObject*
+Term_coefficient( Term* self )
+{
+ return PyFloat_FromDouble( self->coefficient );
+}
+
+
+static PyObject*
+Term_value( Term* self )
+{
+ Variable* pyvar = reinterpret_cast<Variable*>( self->variable );
+ return PyFloat_FromDouble( self->coefficient * pyvar->variable.value() );
+}
+
+
+static PyObject*
+Term_add( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryAdd, Term>()( first, second );
+}
+
+
+static PyObject*
+Term_sub( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinarySub, Term>()( first, second );
+}
+
+
+static PyObject*
+Term_mul( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryMul, Term>()( first, second );
+}
+
+
+static PyObject*
+Term_div( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryDiv, Term>()( first, second );
+}
+
+
+static PyObject*
+Term_neg( PyObject* value )
+{
+ return UnaryInvoke<UnaryNeg, Term>()( value );
+}
+
+
+static PyObject*
+Term_richcmp( PyObject* first, PyObject* second, int op )
+{
+ switch( op )
+ {
+ case Py_EQ:
+ return BinaryInvoke<CmpEQ, Term>()( first, second );
+ case Py_LE:
+ return BinaryInvoke<CmpLE, Term>()( first, second );
+ case Py_GE:
+ return BinaryInvoke<CmpGE, Term>()( first, second );
+ default:
+ break;
+ }
+ PyErr_Format(
+ PyExc_TypeError,
+ "unsupported operand type(s) for %s: "
+ "'%.100s' and '%.100s'",
+ pyop_str( op ),
+ first->ob_type->tp_name,
+ second->ob_type->tp_name
+ );
+ return 0;
+}
+
+
+static PyMethodDef
+Term_methods[] = {
+ { "variable", ( PyCFunction )Term_variable, METH_NOARGS,
+ "Get the variable for the term." },
+ { "coefficient", ( PyCFunction )Term_coefficient, METH_NOARGS,
+ "Get the coefficient for the term." },
+ { "value", ( PyCFunction )Term_value, METH_NOARGS,
+ "Get the value for the term." },
+ { 0 } // sentinel
+};
+
+
+static PyNumberMethods
+Term_as_number = {
+ (binaryfunc)Term_add, /* nb_add */
+ (binaryfunc)Term_sub, /* nb_subtract */
+ (binaryfunc)Term_mul, /* nb_multiply */
+#if PY_MAJOR_VERSION < 3
+ (binaryfunc)Term_div, /* nb_divide */
+#endif
+ 0, /* nb_remainder */
+ 0, /* nb_divmod */
+ 0, /* nb_power */
+ (unaryfunc)Term_neg, /* nb_negative */
+ 0, /* nb_positive */
+ 0, /* nb_absolute */
+#if PY_MAJOR_VERSION >= 3
+ 0, /* nb_bool */
+#else
+ 0, /* nb_nonzero */
+#endif
+ 0, /* nb_invert */
+ 0, /* nb_lshift */
+ 0, /* nb_rshift */
+ 0, /* nb_and */
+ 0, /* nb_xor */
+ (binaryfunc)0, /* nb_or */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_coerce */
+#endif
+ 0, /* nb_int */
+ 0, /* nb_long */
+ 0, /* nb_float */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_oct */
+ 0, /* nb_hex */
+#endif
+ 0, /* nb_inplace_add */
+ 0, /* nb_inplace_subtract */
+ 0, /* nb_inplace_multiply */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_inplace_divide */
+#endif
+ 0, /* nb_inplace_remainder */
+ 0, /* nb_inplace_power */
+ 0, /* nb_inplace_lshift */
+ 0, /* nb_inplace_rshift */
+ 0, /* nb_inplace_and */
+ 0, /* nb_inplace_xor */
+ 0, /* nb_inplace_or */
+ (binaryfunc)0, /* nb_floor_divide */
+ (binaryfunc)Term_div, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+#if PY_VERSION_HEX >= 0x02050000
+ (unaryfunc)0, /* nb_index */
+#endif
+#if PY_VERSION_HEX >= 0x03050000
+ (binaryfunc)0, /* nb_matrix_multiply */
+ (binaryfunc)0, /* nb_inplace_matrix_multiply */
+#endif
+};
+
+
+PyTypeObject Term_Type = {
+ PyVarObject_HEAD_INIT( &PyType_Type, 0 )
+ "kiwisolver.Term", /* tp_name */
+ sizeof( Term ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Term_dealloc, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03050000
+ ( PyAsyncMethods* )0, /* tp_as_async */
+#elif PY_VERSION_HEX >= 0x03000000
+ ( void* ) 0, /* tp_reserved */
+#else
+ ( cmpfunc )0, /* tp_compare */
+#endif
+ (reprfunc)Term_repr, /* tp_repr */
+ (PyNumberMethods*)&Term_as_number, /* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+#if PY_MAJOR_VERSION >= 3
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, /* tp_flags */
+#else
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+#endif
+ 0, /* Documentation string */
+ (traverseproc)Term_traverse, /* tp_traverse */
+ (inquiry)Term_clear, /* tp_clear */
+ (richcmpfunc)Term_richcmp, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)Term_methods, /* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)Term_new, /* tp_new */
+ (freefunc)PyObject_GC_Del, /* tp_free */
+ (inquiry)0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ (destructor)0 /* tp_del */
+};
+
+
+int import_term()
+{
+ return PyType_Ready( &Term_Type );
+}
diff --git a/contrib/python/kiwisolver/py2/py/types.h b/contrib/python/kiwisolver/py2/py/types.h
new file mode 100644
index 00000000000..628efafbca4
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/py/types.h
@@ -0,0 +1,112 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <Python.h>
+#include <kiwi/kiwi.h>
+
+
+int import_variable();
+
+int import_term();
+
+int import_expression();
+
+int import_constraint();
+
+int import_solver();
+
+int import_strength();
+
+
+extern PyTypeObject Variable_Type;
+
+extern PyTypeObject Term_Type;
+
+extern PyTypeObject Expression_Type;
+
+extern PyTypeObject Constraint_Type;
+
+extern PyTypeObject Solver_Type;
+
+extern PyTypeObject strength_Type;
+
+extern PyObject* DuplicateConstraint;
+
+extern PyObject* UnsatisfiableConstraint;
+
+extern PyObject* UnknownConstraint;
+
+extern PyObject* DuplicateEditVariable;
+
+extern PyObject* UnknownEditVariable;
+
+extern PyObject* BadRequiredStrength;
+
+
+struct Variable
+{
+ PyObject_HEAD
+ PyObject* context;
+ kiwi::Variable variable;
+
+ static bool TypeCheck( PyObject* obj )
+ {
+ return PyObject_TypeCheck( obj, &Variable_Type ) != 0;
+ }
+};
+
+
+struct Term
+{
+ PyObject_HEAD
+ PyObject* variable;
+ double coefficient;
+
+ static bool TypeCheck( PyObject* obj )
+ {
+ return PyObject_TypeCheck( obj, &Term_Type ) != 0;
+ }
+};
+
+
+struct Expression
+{
+ PyObject_HEAD
+ PyObject* terms;
+ double constant;
+
+ static bool TypeCheck( PyObject* obj )
+ {
+ return PyObject_TypeCheck( obj, &Expression_Type ) != 0;
+ }
+};
+
+
+struct Constraint
+{
+ PyObject_HEAD
+ PyObject* expression;
+ kiwi::Constraint constraint;
+
+ static bool TypeCheck( PyObject* obj )
+ {
+ return PyObject_TypeCheck( obj, &Constraint_Type ) != 0;
+ }
+};
+
+
+struct Solver
+{
+ PyObject_HEAD
+ kiwi::Solver solver;
+
+ static bool TypeCheck( PyObject* obj )
+ {
+ return PyObject_TypeCheck( obj, &Solver_Type ) != 0;
+ }
+};
diff --git a/contrib/python/kiwisolver/py2/py/util.h b/contrib/python/kiwisolver/py2/py/util.h
new file mode 100644
index 00000000000..78e9cbd0b8e
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/py/util.h
@@ -0,0 +1,230 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <map>
+#include <string>
+#include <Python.h>
+#include <kiwi/kiwi.h>
+#include "pythonhelpers.h"
+#include "types.h"
+
+
+inline bool
+convert_to_double( PyObject* obj, double& out )
+{
+ if( PyFloat_Check( obj ) )
+ {
+ out = PyFloat_AS_DOUBLE( obj );
+ return true;
+ }
+#if PY_MAJOR_VERSION < 3
+ if( PyInt_Check( obj ) )
+ {
+ out = double( PyInt_AsLong( obj ) );
+ return true;
+ }
+#endif
+ if( PyLong_Check( obj ) )
+ {
+ out = PyLong_AsDouble( obj );
+ if( out == -1.0 && PyErr_Occurred() )
+ return false;
+ return true;
+ }
+ PythonHelpers::py_expected_type_fail( obj, "float, int, or long" );
+ return false;
+}
+
+
+inline bool
+convert_pystr_to_str( PyObject* value, std::string& out )
+{
+#if PY_MAJOR_VERSION >= 3
+ out = PyUnicode_AsUTF8( value );
+#else
+ if( PyUnicode_Check( value ) )
+ {
+ PythonHelpers::PyObjectPtr py_str( PyUnicode_AsUTF8String( value ) );
+ if( !py_str )
+ return false; // LCOV_EXCL_LINE
+ out = PyString_AS_STRING( py_str.get() );
+ }
+ else
+ out = PyString_AS_STRING( value );
+#endif
+ return true;
+}
+
+
+inline bool
+convert_to_strength( PyObject* value, double& out )
+{
+#if PY_MAJOR_VERSION >= 3
+ if( PyUnicode_Check( value ) )
+ {
+#else
+ if( PyString_Check( value ) | PyUnicode_Check( value ))
+ {
+#endif
+ std::string str;
+ if( !convert_pystr_to_str( value, str ) )
+ return false;
+ if( str == "required" )
+ out = kiwi::strength::required;
+ else if( str == "strong" )
+ out = kiwi::strength::strong;
+ else if( str == "medium" )
+ out = kiwi::strength::medium;
+ else if( str == "weak" )
+ out = kiwi::strength::weak;
+ else
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "string strength must be 'required', 'strong', 'medium', "
+ "or 'weak', not '%s'",
+ str.c_str()
+ );
+ return false;
+ }
+ return true;
+ }
+ if( !convert_to_double( value, out ) )
+ return false;
+ return true;
+}
+
+
+inline bool
+convert_to_relational_op( PyObject* value, kiwi::RelationalOperator& out )
+{
+#if PY_MAJOR_VERSION >= 3
+ if( !PyUnicode_Check( value ) )
+ {
+ PythonHelpers::py_expected_type_fail( value, "unicode" );
+ return false;
+ }
+#else
+ if( !(PyString_Check( value ) | PyUnicode_Check( value ) ) )
+ {
+ PythonHelpers::py_expected_type_fail( value, "str or unicode" );
+ return false;
+ }
+#endif
+ std::string str;
+ if( !convert_pystr_to_str( value, str ) )
+ return false;
+ if( str == "==" )
+ out = kiwi::OP_EQ;
+ else if( str == "<=" )
+ out = kiwi::OP_LE;
+ else if( str == ">=" )
+ out = kiwi::OP_GE;
+ else
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "relational operator must be '==', '<=', or '>=', not '%s'",
+ str.c_str()
+ );
+ return false;
+ }
+ return true;
+}
+
+
+inline PyObject*
+make_terms( const std::map<PyObject*, double>& coeffs )
+{
+ typedef std::map<PyObject*, double>::const_iterator iter_t;
+ PythonHelpers::PyObjectPtr terms( PyTuple_New( coeffs.size() ) );
+ if( !terms )
+ return 0;
+ Py_ssize_t size = PyTuple_GET_SIZE( terms.get() );
+ for( Py_ssize_t i = 0; i < size; ++i ) // zero tuple for safe early return
+ PyTuple_SET_ITEM( terms.get(), i, 0 );
+ Py_ssize_t i = 0;
+ iter_t it = coeffs.begin();
+ iter_t end = coeffs.end();
+ for( ; it != end; ++it, ++i )
+ {
+ PyObject* pyterm = PyType_GenericNew( &Term_Type, 0, 0 );
+ if( !pyterm )
+ return 0;
+ Term* term = reinterpret_cast<Term*>( pyterm );
+ term->variable = PythonHelpers::newref( it->first );
+ term->coefficient = it->second;
+ PyTuple_SET_ITEM( terms.get(), i, pyterm );
+ }
+ return terms.release();
+}
+
+
+inline PyObject*
+reduce_expression( PyObject* pyexpr ) // pyexpr must be an Expression
+{
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr );
+ std::map<PyObject*, double> coeffs;
+ Py_ssize_t size = PyTuple_GET_SIZE( expr->terms );
+ for( Py_ssize_t i = 0; i < size; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( expr->terms, i );
+ Term* term = reinterpret_cast<Term*>( item );
+ coeffs[ term->variable ] += term->coefficient;
+ }
+ PythonHelpers::PyObjectPtr terms( make_terms( coeffs ) );
+ if( !terms )
+ return 0;
+ PyObject* pynewexpr = PyType_GenericNew( &Expression_Type, 0, 0 );
+ if( !pynewexpr )
+ return 0;
+ Expression* newexpr = reinterpret_cast<Expression*>( pynewexpr );
+ newexpr->terms = terms.release();
+ newexpr->constant = expr->constant;
+ return pynewexpr;
+}
+
+
+inline kiwi::Expression
+convert_to_kiwi_expression( PyObject* pyexpr ) // pyexpr must be an Expression
+{
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr );
+ std::vector<kiwi::Term> kterms;
+ Py_ssize_t size = PyTuple_GET_SIZE( expr->terms );
+ for( Py_ssize_t i = 0; i < size; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( expr->terms, i );
+ Term* term = reinterpret_cast<Term*>( item );
+ Variable* var = reinterpret_cast<Variable*>( term->variable );
+ kterms.push_back( kiwi::Term( var->variable, term->coefficient ) );
+ }
+ return kiwi::Expression( kterms, expr->constant );
+}
+
+
+inline const char*
+pyop_str( int op )
+{
+ switch( op )
+ {
+ case Py_LT:
+ return "<";
+ case Py_LE:
+ return "<=";
+ case Py_EQ:
+ return "==";
+ case Py_NE:
+ return "!=";
+ case Py_GT:
+ return ">";
+ case Py_GE:
+ return ">=";
+ default:
+ return "";
+ }
+}
diff --git a/contrib/python/kiwisolver/py2/py/variable.cpp b/contrib/python/kiwisolver/py2/py/variable.cpp
new file mode 100644
index 00000000000..a622e8529ab
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/py/variable.cpp
@@ -0,0 +1,353 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <Python.h>
+#include <kiwi/kiwi.h>
+#include "pythonhelpers.h"
+#include "symbolics.h"
+#include "types.h"
+#include "util.h"
+
+
+using namespace PythonHelpers;
+
+
+static PyObject*
+Variable_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
+{
+ static const char *kwlist[] = { "name", "context", 0 };
+ PyObject* context = 0;
+ PyObject* name = 0;
+
+ if( !PyArg_ParseTupleAndKeywords(
+ args, kwargs, "|OO:__new__", const_cast<char**>( kwlist ),
+ &name, &context ) )
+ return 0;
+
+ PyObjectPtr pyvar( PyType_GenericNew( type, args, kwargs ) );
+ if( !pyvar )
+ return 0;
+
+ Variable* self = reinterpret_cast<Variable*>( pyvar.get() );
+ self->context = xnewref( context );
+
+ if( name != 0 )
+ {
+#if PY_MAJOR_VERSION >= 3
+ if( !PyUnicode_Check( name ) )
+ return py_expected_type_fail( name, "unicode" );
+#else
+ if( !( PyString_Check( name ) | PyUnicode_Check( name ) ) )
+ {
+ return py_expected_type_fail( name, "str or unicode" );
+ }
+#endif
+ std::string c_name;
+ if( !convert_pystr_to_str(name, c_name) )
+ return 0; // LCOV_EXCL_LINE
+ new( &self->variable ) kiwi::Variable( c_name );
+ }
+ else
+ {
+ new( &self->variable ) kiwi::Variable();
+ }
+
+ return pyvar.release();
+}
+
+
+static void
+Variable_clear( Variable* self )
+{
+ Py_CLEAR( self->context );
+}
+
+
+static int
+Variable_traverse( Variable* self, visitproc visit, void* arg )
+{
+ Py_VISIT( self->context );
+ return 0;
+}
+
+
+static void
+Variable_dealloc( Variable* self )
+{
+ PyObject_GC_UnTrack( self );
+ Variable_clear( self );
+ self->variable.~Variable();
+ Py_TYPE( self )->tp_free( pyobject_cast( self ) );
+}
+
+
+static PyObject*
+Variable_repr( Variable* self )
+{
+ return FROM_STRING( self->variable.name().c_str() );
+}
+
+
+static PyObject*
+Variable_name( Variable* self )
+{
+ return FROM_STRING( self->variable.name().c_str() );
+}
+
+
+static PyObject*
+Variable_setName( Variable* self, PyObject* pystr )
+{
+#if PY_MAJOR_VERSION >= 3
+ if( !PyUnicode_Check( pystr ) )
+ return py_expected_type_fail( pystr, "unicode" );
+#else
+ if( !(PyString_Check( pystr ) | PyUnicode_Check( pystr ) ) )
+ {
+ return py_expected_type_fail( pystr, "str or unicode" );
+ }
+#endif
+ std::string str;
+ if( !convert_pystr_to_str( pystr, str ) )
+ return 0;
+ self->variable.setName( str );
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Variable_context( Variable* self )
+{
+ if( self->context )
+ return newref( self->context );
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Variable_setContext( Variable* self, PyObject* value )
+{
+ if( value != self->context )
+ {
+ PyObject* temp = self->context;
+ self->context = newref( value );
+ Py_XDECREF( temp );
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Variable_value( Variable* self )
+{
+ return PyFloat_FromDouble( self->variable.value() );
+}
+
+
+static PyObject*
+Variable_add( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryAdd, Variable>()( first, second );
+}
+
+
+static PyObject*
+Variable_sub( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinarySub, Variable>()( first, second );
+}
+
+
+static PyObject*
+Variable_mul( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryMul, Variable>()( first, second );
+}
+
+
+static PyObject*
+Variable_div( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryDiv, Variable>()( first, second );
+}
+
+
+static PyObject*
+Variable_neg( PyObject* value )
+{
+ return UnaryInvoke<UnaryNeg, Variable>()( value );
+}
+
+
+static PyObject*
+Variable_richcmp( PyObject* first, PyObject* second, int op )
+{
+ switch( op )
+ {
+ case Py_EQ:
+ return BinaryInvoke<CmpEQ, Variable>()( first, second );
+ case Py_LE:
+ return BinaryInvoke<CmpLE, Variable>()( first, second );
+ case Py_GE:
+ return BinaryInvoke<CmpGE, Variable>()( first, second );
+ default:
+ break;
+ }
+ PyErr_Format(
+ PyExc_TypeError,
+ "unsupported operand type(s) for %s: "
+ "'%.100s' and '%.100s'",
+ pyop_str( op ),
+ first->ob_type->tp_name,
+ second->ob_type->tp_name
+ );
+ return 0;
+}
+
+
+static PyMethodDef
+Variable_methods[] = {
+ { "name", ( PyCFunction )Variable_name, METH_NOARGS,
+ "Get the name of the variable." },
+ { "setName", ( PyCFunction )Variable_setName, METH_O,
+ "Set the name of the variable." },
+ { "context", ( PyCFunction )Variable_context, METH_NOARGS,
+ "Get the context object associated with the variable." },
+ { "setContext", ( PyCFunction )Variable_setContext, METH_O,
+ "Set the context object associated with the variable." },
+ { "value", ( PyCFunction )Variable_value, METH_NOARGS,
+ "Get the current value of the variable." },
+ { 0 } // sentinel
+};
+
+
+static PyNumberMethods
+Variable_as_number = {
+ (binaryfunc)Variable_add, /* nb_add */
+ (binaryfunc)Variable_sub, /* nb_subtract */
+ (binaryfunc)Variable_mul, /* nb_multiply */
+#if PY_MAJOR_VERSION < 3
+ (binaryfunc)Variable_div, /* nb_divide */
+#endif
+ 0, /* nb_remainder */
+ 0, /* nb_divmod */
+ 0, /* nb_power */
+ (unaryfunc)Variable_neg, /* nb_negative */
+ 0, /* nb_positive */
+ 0, /* nb_absolute */
+#if PY_MAJOR_VERSION >= 3
+ 0, /* nb_bool */
+#else
+ 0, /* nb_nonzero */
+#endif
+ 0, /* nb_invert */
+ 0, /* nb_lshift */
+ 0, /* nb_rshift */
+ 0, /* nb_and */
+ 0, /* nb_xor */
+ (binaryfunc)0, /* nb_or */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_coerce */
+#endif
+ 0, /* nb_int */
+ 0, /* nb_long */
+ 0, /* nb_float */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_oct */
+ 0, /* nb_hex */
+#endif
+ 0, /* nb_inplace_add */
+ 0, /* nb_inplace_subtract */
+ 0, /* nb_inplace_multiply */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_inplace_divide */
+#endif
+ 0, /* nb_inplace_remainder */
+ 0, /* nb_inplace_power */
+ 0, /* nb_inplace_lshift */
+ 0, /* nb_inplace_rshift */
+ 0, /* nb_inplace_and */
+ 0, /* nb_inplace_xor */
+ 0, /* nb_inplace_or */
+ (binaryfunc)0, /* nb_floor_divide */
+ (binaryfunc)Variable_div, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+#if PY_VERSION_HEX >= 0x02050000
+ (unaryfunc)0, /* nb_index */
+#endif
+#if PY_VERSION_HEX >= 0x03050000
+ (binaryfunc)0, /* nb_matrix_multiply */
+ (binaryfunc)0, /* nb_inplace_matrix_multiply */
+#endif
+};
+
+
+PyTypeObject Variable_Type = {
+ PyVarObject_HEAD_INIT( &PyType_Type, 0 )
+ "kiwisolver.Variable", /* tp_name */
+ sizeof( Variable ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Variable_dealloc, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03050000
+ ( PyAsyncMethods* )0, /* tp_as_async */
+#elif PY_VERSION_HEX >= 0x03000000
+ ( void* ) 0, /* tp_reserved */
+#else
+ ( cmpfunc )0, /* tp_compare */
+#endif
+ (reprfunc)Variable_repr, /* tp_repr */
+ (PyNumberMethods*)&Variable_as_number, /* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+#if PY_MAJOR_VERSION >= 3
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, /* tp_flags */
+#else
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+#endif
+ 0, /* Documentation string */
+ (traverseproc)Variable_traverse, /* tp_traverse */
+ (inquiry)Variable_clear, /* tp_clear */
+ (richcmpfunc)Variable_richcmp, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)Variable_methods, /* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)Variable_new, /* tp_new */
+ (freefunc)PyObject_GC_Del, /* tp_free */
+ (inquiry)0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ (destructor)0 /* tp_del */
+};
+
+
+int import_variable()
+{
+ return PyType_Ready( &Variable_Type );
+}
diff --git a/contrib/python/kiwisolver/py2/ya.make b/contrib/python/kiwisolver/py2/ya.make
new file mode 100644
index 00000000000..3803e254093
--- /dev/null
+++ b/contrib/python/kiwisolver/py2/ya.make
@@ -0,0 +1,41 @@
+# Generated by devtools/yamaker (pypi).
+
+PY2_LIBRARY()
+
+VERSION(1.1.0)
+
+LICENSE(BSD-3-Clause)
+
+PEERDIR(
+ contrib/python/setuptools
+)
+
+ADDINCL(
+ contrib/python/kiwisolver/py2
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_LINT()
+
+SRCS(
+ py/constraint.cpp
+ py/expression.cpp
+ py/kiwisolver.cpp
+ py/solver.cpp
+ py/strength.cpp
+ py/term.cpp
+ py/variable.cpp
+)
+
+PY_REGISTER(
+ kiwisolver
+)
+
+RESOURCE_FILES(
+ PREFIX contrib/python/kiwisolver/py2/
+ .dist-info/METADATA
+ .dist-info/top_level.txt
+)
+
+END()
diff --git a/contrib/python/kiwisolver/py3/.dist-info/METADATA b/contrib/python/kiwisolver/py3/.dist-info/METADATA
new file mode 100644
index 00000000000..6c363cae42f
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/.dist-info/METADATA
@@ -0,0 +1,42 @@
+Metadata-Version: 2.1
+Name: kiwisolver
+Version: 1.1.0
+Summary: A fast implementation of the Cassowary constraint solver
+Home-page: https://github.com/nucleic/kiwi
+Author: The Nucleic Development Team
+Author-email: [email protected]
+License: BSD
+Platform: UNKNOWN
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
+Requires-Dist: setuptools
+
+Welcome to Kiwi
+===============
+
+.. image:: https://travis-ci.org/nucleic/kiwi.svg?branch=master
+ :target: https://travis-ci.org/nucleic/kiwi
+.. image:: https://codecov.io/gh/nucleic/kiwi/branch/master/graph/badge.svg
+ :target: https://codecov.io/gh/nucleic/kiwi
+.. image:: https://readthedocs.org/projects/kiwisolver/badge/?version=latest
+ :target: https://kiwisolver.readthedocs.io/en/latest/?badge=latest
+ :alt: Documentation Status
+
+Kiwi is an efficient C++ implementation of the Cassowary constraint solving
+algorithm. Kiwi is an implementation of the algorithm based on the seminal
+Cassowary paper. It is *not* a refactoring of the original C++ solver. Kiwi
+has been designed from the ground up to be lightweight and fast. Kiwi ranges
+from 10x to 500x faster than the original Cassowary solver with typical use
+cases gaining a 40x improvement. Memory savings are consistently > 5x.
+
+In addition to the C++ solver, Kiwi ships with hand-rolled Python bindings.
+
+
diff --git a/contrib/python/kiwisolver/py3/.dist-info/top_level.txt b/contrib/python/kiwisolver/py3/.dist-info/top_level.txt
new file mode 100644
index 00000000000..9b85884d1a9
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/.dist-info/top_level.txt
@@ -0,0 +1 @@
+kiwisolver
diff --git a/contrib/python/kiwisolver/py3/README.rst b/contrib/python/kiwisolver/py3/README.rst
new file mode 100644
index 00000000000..4faa3c329ba
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/README.rst
@@ -0,0 +1,19 @@
+Welcome to Kiwi
+===============
+
+.. image:: https://travis-ci.org/nucleic/kiwi.svg?branch=master
+ :target: https://travis-ci.org/nucleic/kiwi
+.. image:: https://codecov.io/gh/nucleic/kiwi/branch/master/graph/badge.svg
+ :target: https://codecov.io/gh/nucleic/kiwi
+.. image:: https://readthedocs.org/projects/kiwisolver/badge/?version=latest
+ :target: https://kiwisolver.readthedocs.io/en/latest/?badge=latest
+ :alt: Documentation Status
+
+Kiwi is an efficient C++ implementation of the Cassowary constraint solving
+algorithm. Kiwi is an implementation of the algorithm based on the seminal
+Cassowary paper. It is *not* a refactoring of the original C++ solver. Kiwi
+has been designed from the ground up to be lightweight and fast. Kiwi ranges
+from 10x to 500x faster than the original Cassowary solver with typical use
+cases gaining a 40x improvement. Memory savings are consistently > 5x.
+
+In addition to the C++ solver, Kiwi ships with hand-rolled Python bindings.
diff --git a/contrib/python/kiwisolver/py3/kiwi/AssocVector.h b/contrib/python/kiwisolver/py3/kiwi/AssocVector.h
new file mode 100644
index 00000000000..0d5eb288efc
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/AssocVector.h
@@ -0,0 +1,354 @@
+////////////////////////////////////////////////////////////////////////////////
+// The Loki Library
+// Copyright (c) 2001 by Andrei Alexandrescu
+// This code accompanies the book:
+// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
+// Patterns Applied". Copyright (c) 2001. Addison-Wesley.
+// Permission to use, copy, modify, distribute and sell this software for any
+// purpose is hereby granted without fee, provided that the above copyright
+// notice appear in all copies and that both that copyright notice and this
+// permission notice appear in supporting documentation.
+// The author or Addison-Wesley Longman make no representations about the
+// suitability of this software for any purpose. It is provided "as is"
+// without express or implied warranty.
+////////////////////////////////////////////////////////////////////////////////
+#pragma once
+
+// $Id: AssocVector.h 765 2006-10-18 13:55:32Z syntheticpp $
+
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+#include <utility>
+
+namespace Loki
+{
+////////////////////////////////////////////////////////////////////////////////
+// class template AssocVectorCompare
+// Used by AssocVector
+////////////////////////////////////////////////////////////////////////////////
+
+ namespace Private
+ {
+ template <class Value, class C>
+ class AssocVectorCompare : public C
+ {
+ typedef std::pair<typename C::first_argument_type, Value>
+ Data;
+ typedef typename C::first_argument_type first_argument_type;
+
+ public:
+ AssocVectorCompare()
+ {}
+
+ AssocVectorCompare(const C& src) : C(src)
+ {}
+
+ bool operator()(const first_argument_type& lhs,
+ const first_argument_type& rhs) const
+ { return C::operator()(lhs, rhs); }
+
+ bool operator()(const Data& lhs, const Data& rhs) const
+ { return operator()(lhs.first, rhs.first); }
+
+ bool operator()(const Data& lhs,
+ const first_argument_type& rhs) const
+ { return operator()(lhs.first, rhs); }
+
+ bool operator()(const first_argument_type& lhs,
+ const Data& rhs) const
+ { return operator()(lhs, rhs.first); }
+ };
+ }
+
+////////////////////////////////////////////////////////////////////////////////
+// class template AssocVector
+// An associative vector built as a syntactic drop-in replacement for std::map
+// BEWARE: AssocVector doesn't respect all map's guarantees, the most important
+// being:
+// * iterators are invalidated by insert and erase operations
+// * the complexity of insert/erase is O(N) not O(log N)
+// * value_type is std::pair<K, V> not std::pair<const K, V>
+// * iterators are random
+////////////////////////////////////////////////////////////////////////////////
+
+
+ template
+ <
+ class K,
+ class V,
+ class C = std::less<K>,
+ class A = std::allocator< std::pair<K, V> >
+ >
+ class AssocVector
+ : private std::vector< std::pair<K, V>, A >
+ , private Private::AssocVectorCompare<V, C>
+ {
+ typedef std::vector<std::pair<K, V>, A> Base;
+ typedef Private::AssocVectorCompare<V, C> MyCompare;
+
+ public:
+ typedef K key_type;
+ typedef V mapped_type;
+ typedef typename Base::value_type value_type;
+
+ typedef C key_compare;
+ typedef A allocator_type;
+ typedef typename A::reference reference;
+ typedef typename A::const_reference const_reference;
+ typedef typename Base::iterator iterator;
+ typedef typename Base::const_iterator const_iterator;
+ typedef typename Base::size_type size_type;
+ typedef typename Base::difference_type difference_type;
+ typedef typename A::pointer pointer;
+ typedef typename A::const_pointer const_pointer;
+ typedef typename Base::reverse_iterator reverse_iterator;
+ typedef typename Base::const_reverse_iterator const_reverse_iterator;
+
+ class value_compare
+ : public std::binary_function<value_type, value_type, bool>
+ , private key_compare
+ {
+ friend class AssocVector;
+
+ protected:
+ value_compare(key_compare pred) : key_compare(pred)
+ {}
+
+ public:
+ bool operator()(const value_type& lhs, const value_type& rhs) const
+ { return key_compare::operator()(lhs.first, rhs.first); }
+ };
+
+ // 23.3.1.1 construct/copy/destroy
+
+ explicit AssocVector(const key_compare& comp = key_compare(),
+ const A& alloc = A())
+ : Base(alloc), MyCompare(comp)
+ {}
+
+ template <class InputIterator>
+ AssocVector(InputIterator first, InputIterator last,
+ const key_compare& comp = key_compare(),
+ const A& alloc = A())
+ : Base(first, last, alloc), MyCompare(comp)
+ {
+ MyCompare& me = *this;
+ std::sort(begin(), end(), me);
+ }
+
+ AssocVector& operator=(const AssocVector& rhs)
+ {
+ AssocVector(rhs).swap(*this);
+ return *this;
+ }
+
+ // iterators:
+ // The following are here because MWCW gets 'using' wrong
+ iterator begin() { return Base::begin(); }
+ const_iterator begin() const { return Base::begin(); }
+ iterator end() { return Base::end(); }
+ const_iterator end() const { return Base::end(); }
+ reverse_iterator rbegin() { return Base::rbegin(); }
+ const_reverse_iterator rbegin() const { return Base::rbegin(); }
+ reverse_iterator rend() { return Base::rend(); }
+ const_reverse_iterator rend() const { return Base::rend(); }
+
+ // capacity:
+ bool empty() const { return Base::empty(); }
+ size_type size() const { return Base::size(); }
+ size_type max_size() { return Base::max_size(); }
+
+ // 23.3.1.2 element access:
+ mapped_type& operator[](const key_type& key)
+ { return insert(value_type(key, mapped_type())).first->second; }
+
+ // modifiers:
+ std::pair<iterator, bool> insert(const value_type& val)
+ {
+ bool found(true);
+ iterator i(lower_bound(val.first));
+
+ if (i == end() || this->operator()(val.first, i->first))
+ {
+ i = Base::insert(i, val);
+ found = false;
+ }
+ return std::make_pair(i, !found);
+ }
+ //Section [23.1.2], Table 69
+ //http://developer.apple.com/documentation/DeveloperTools/gcc-3.3/libstdc++/23_containers/howto.html#4
+ iterator insert(iterator pos, const value_type& val)
+ {
+ if( (pos == begin() || this->operator()(*(pos-1),val)) &&
+ (pos == end() || this->operator()(val, *pos)) )
+ {
+ return Base::insert(pos, val);
+ }
+ return insert(val).first;
+ }
+
+ template <class InputIterator>
+ void insert(InputIterator first, InputIterator last)
+ { for (; first != last; ++first) insert(*first); }
+
+ void erase(iterator pos)
+ { Base::erase(pos); }
+
+ size_type erase(const key_type& k)
+ {
+ iterator i(find(k));
+ if (i == end()) return 0;
+ erase(i);
+ return 1;
+ }
+
+ void erase(iterator first, iterator last)
+ { Base::erase(first, last); }
+
+ void swap(AssocVector& other)
+ {
+ Base::swap(other);
+ MyCompare& me = *this;
+ MyCompare& rhs = other;
+ std::swap(me, rhs);
+ }
+
+ void clear()
+ { Base::clear(); }
+
+ // observers:
+ key_compare key_comp() const
+ { return *this; }
+
+ value_compare value_comp() const
+ {
+ const key_compare& comp = *this;
+ return value_compare(comp);
+ }
+
+ // 23.3.1.3 map operations:
+ iterator find(const key_type& k)
+ {
+ iterator i(lower_bound(k));
+ if (i != end() && this->operator()(k, i->first))
+ {
+ i = end();
+ }
+ return i;
+ }
+
+ const_iterator find(const key_type& k) const
+ {
+ const_iterator i(lower_bound(k));
+ if (i != end() && this->operator()(k, i->first))
+ {
+ i = end();
+ }
+ return i;
+ }
+
+ size_type count(const key_type& k) const
+ { return find(k) != end(); }
+
+ iterator lower_bound(const key_type& k)
+ {
+ MyCompare& me = *this;
+ return std::lower_bound(begin(), end(), k, me);
+ }
+
+ const_iterator lower_bound(const key_type& k) const
+ {
+ const MyCompare& me = *this;
+ return std::lower_bound(begin(), end(), k, me);
+ }
+
+ iterator upper_bound(const key_type& k)
+ {
+ MyCompare& me = *this;
+ return std::upper_bound(begin(), end(), k, me);
+ }
+
+ const_iterator upper_bound(const key_type& k) const
+ {
+ const MyCompare& me = *this;
+ return std::upper_bound(begin(), end(), k, me);
+ }
+
+ std::pair<iterator, iterator> equal_range(const key_type& k)
+ {
+ MyCompare& me = *this;
+ return std::equal_range(begin(), end(), k, me);
+ }
+
+ std::pair<const_iterator, const_iterator> equal_range(
+ const key_type& k) const
+ {
+ const MyCompare& me = *this;
+ return std::equal_range(begin(), end(), k, me);
+ }
+
+ template <class K1, class V1, class C1, class A1>
+ friend bool operator==(const AssocVector<K1, V1, C1, A1>& lhs,
+ const AssocVector<K1, V1, C1, A1>& rhs);
+
+ bool operator<(const AssocVector& rhs) const
+ {
+ const Base& me = *this;
+ const Base& yo = rhs;
+ return me < yo;
+ }
+
+ template <class K1, class V1, class C1, class A1>
+ friend bool operator!=(const AssocVector<K1, V1, C1, A1>& lhs,
+ const AssocVector<K1, V1, C1, A1>& rhs);
+
+ template <class K1, class V1, class C1, class A1>
+ friend bool operator>(const AssocVector<K1, V1, C1, A1>& lhs,
+ const AssocVector<K1, V1, C1, A1>& rhs);
+
+ template <class K1, class V1, class C1, class A1>
+ friend bool operator>=(const AssocVector<K1, V1, C1, A1>& lhs,
+ const AssocVector<K1, V1, C1, A1>& rhs);
+
+ template <class K1, class V1, class C1, class A1>
+ friend bool operator<=(const AssocVector<K1, V1, C1, A1>& lhs,
+ const AssocVector<K1, V1, C1, A1>& rhs);
+ };
+
+ template <class K, class V, class C, class A>
+ inline bool operator==(const AssocVector<K, V, C, A>& lhs,
+ const AssocVector<K, V, C, A>& rhs)
+ {
+ const std::vector<std::pair<K, V>, A>& me = lhs;
+ return me == rhs;
+ }
+
+ template <class K, class V, class C, class A>
+ inline bool operator!=(const AssocVector<K, V, C, A>& lhs,
+ const AssocVector<K, V, C, A>& rhs)
+ { return !(lhs == rhs); }
+
+ template <class K, class V, class C, class A>
+ inline bool operator>(const AssocVector<K, V, C, A>& lhs,
+ const AssocVector<K, V, C, A>& rhs)
+ { return rhs < lhs; }
+
+ template <class K, class V, class C, class A>
+ inline bool operator>=(const AssocVector<K, V, C, A>& lhs,
+ const AssocVector<K, V, C, A>& rhs)
+ { return !(lhs < rhs); }
+
+ template <class K, class V, class C, class A>
+ inline bool operator<=(const AssocVector<K, V, C, A>& lhs,
+ const AssocVector<K, V, C, A>& rhs)
+ { return !(rhs < lhs); }
+
+
+ // specialized algorithms:
+ template <class K, class V, class C, class A>
+ void swap(AssocVector<K, V, C, A>& lhs, AssocVector<K, V, C, A>& rhs)
+ { lhs.swap(rhs); }
+
+} // namespace Loki
diff --git a/contrib/python/kiwisolver/py3/kiwi/constraint.h b/contrib/python/kiwisolver/py3/kiwi/constraint.h
new file mode 100644
index 00000000000..558dd924aeb
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/constraint.h
@@ -0,0 +1,124 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <map>
+#include <vector>
+#include "expression.h"
+#include "shareddata.h"
+#include "strength.h"
+#include "term.h"
+#include "variable.h"
+
+
+namespace kiwi
+{
+
+enum RelationalOperator { OP_LE, OP_GE, OP_EQ };
+
+
+class Constraint
+{
+
+public:
+
+ Constraint() : m_data( 0 ) {}
+
+ Constraint( const Expression& expr,
+ RelationalOperator op,
+ double strength = strength::required ) :
+ m_data( new ConstraintData( expr, op, strength ) ) {}
+
+ Constraint( const Constraint& other, double strength ) :
+ m_data( new ConstraintData( other, strength ) ) {}
+
+ ~Constraint() {}
+
+ const Expression& expression() const
+ {
+ return m_data->m_expression;
+ }
+
+ RelationalOperator op() const
+ {
+ return m_data->m_op;
+ }
+
+ double strength() const
+ {
+ return m_data->m_strength;
+ }
+
+ bool operator!() const
+ {
+ return !m_data;
+ }
+
+private:
+
+ static Expression reduce( const Expression& expr )
+ {
+ std::map<Variable, double> vars;
+ typedef std::vector<Term>::const_iterator iter_t;
+ iter_t end = expr.terms().end();
+ for( iter_t it = expr.terms().begin(); it != end; ++it )
+ vars[ it->variable() ] += it->coefficient();
+ std::vector<Term> terms( vars.begin(), vars.end() );
+ return Expression( terms, expr.constant() );
+ }
+
+ class ConstraintData : public SharedData
+ {
+
+ public:
+
+ ConstraintData( const Expression& expr,
+ RelationalOperator op,
+ double strength ) :
+ SharedData(),
+ m_expression( reduce( expr ) ),
+ m_strength( strength::clip( strength ) ),
+ m_op( op ) {}
+
+ ConstraintData( const Constraint& other, double strength ) :
+ SharedData(),
+ m_expression( other.expression() ),
+ m_strength( strength::clip( strength ) ),
+ m_op( other.op() ) {}
+
+ ~ConstraintData() {}
+
+ Expression m_expression;
+ double m_strength;
+ RelationalOperator m_op;
+
+ private:
+
+ ConstraintData( const ConstraintData& other );
+
+ ConstraintData& operator=( const ConstraintData& other );
+ };
+
+ SharedDataPtr<ConstraintData> m_data;
+
+ friend bool operator<( const Constraint& lhs, const Constraint& rhs )
+ {
+ return lhs.m_data < rhs.m_data;
+ }
+
+ friend bool operator==( const Constraint& lhs, const Constraint& rhs )
+ {
+ return lhs.m_data == rhs.m_data;
+ }
+
+ friend bool operator!=( const Constraint& lhs, const Constraint& rhs )
+ {
+ return lhs.m_data != rhs.m_data;
+ }
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/debug.h b/contrib/python/kiwisolver/py3/kiwi/debug.h
new file mode 100644
index 00000000000..007a24da5ed
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/debug.h
@@ -0,0 +1,203 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include "constraint.h"
+#include "solverimpl.h"
+#include "term.h"
+
+
+namespace kiwi
+{
+
+namespace impl
+{
+
+class DebugHelper
+{
+
+public:
+
+ static void dump( const SolverImpl& solver, std::ostream& out )
+ {
+ out << "Objective" << std::endl;
+ out << "---------" << std::endl;
+ dump( *solver.m_objective, out );
+ out << std::endl;
+ out << "Tableau" << std::endl;
+ out << "-------" << std::endl;
+ dump( solver.m_rows, out );
+ out << std::endl;
+ out << "Infeasible" << std::endl;
+ out << "----------" << std::endl;
+ dump( solver.m_infeasible_rows, out );
+ out << std::endl;
+ out << "Variables" << std::endl;
+ out << "---------" << std::endl;
+ dump( solver.m_vars, out );
+ out << std::endl;
+ out << "Edit Variables" << std::endl;
+ out << "--------------" << std::endl;
+ dump( solver.m_edits, out );
+ out << std::endl;
+ out << "Constraints" << std::endl;
+ out << "-----------" << std::endl;
+ dump( solver.m_cns, out );
+ out << std::endl;
+ out << std::endl;
+ }
+
+ static void dump( const SolverImpl::RowMap& rows, std::ostream& out )
+ {
+ typedef SolverImpl::RowMap::const_iterator iter_t;
+ iter_t end = rows.end();
+ for( iter_t it = rows.begin(); it != end; ++it )
+ {
+ dump( it->first, out );
+ out << " | ";
+ dump( *it->second, out );
+ }
+ }
+
+ static void dump( const std::vector<Symbol>& symbols, std::ostream& out )
+ {
+ typedef std::vector<Symbol>::const_iterator iter_t;
+ iter_t end = symbols.end();
+ for( iter_t it = symbols.begin(); it != end; ++it )
+ {
+ dump( *it, out );
+ out << std::endl;
+ }
+ }
+
+ static void dump( const SolverImpl::VarMap& vars, std::ostream& out )
+ {
+ typedef SolverImpl::VarMap::const_iterator iter_t;
+ iter_t end = vars.end();
+ for( iter_t it = vars.begin(); it != end; ++it )
+ {
+ out << it->first.name() << " = ";
+ dump( it->second, out );
+ out << std::endl;
+ }
+ }
+
+ static void dump( const SolverImpl::CnMap& cns, std::ostream& out )
+ {
+ typedef SolverImpl::CnMap::const_iterator iter_t;
+ iter_t end = cns.end();
+ for( iter_t it = cns.begin(); it != end; ++it )
+ dump( it->first, out );
+ }
+
+ static void dump( const SolverImpl::EditMap& edits, std::ostream& out )
+ {
+ typedef SolverImpl::EditMap::const_iterator iter_t;
+ iter_t end = edits.end();
+ for( iter_t it = edits.begin(); it != end; ++it )
+ out << it->first.name() << std::endl;
+ }
+
+ static void dump( const Row& row, std::ostream& out )
+ {
+ typedef Row::CellMap::const_iterator iter_t;
+ out << row.constant();
+ iter_t end = row.cells().end();
+ for( iter_t it = row.cells().begin(); it != end; ++it )
+ {
+ out << " + " << it->second << " * ";
+ dump( it->first, out );
+ }
+ out << std::endl;
+ }
+
+ static void dump( const Symbol& symbol, std::ostream& out )
+ {
+ switch( symbol.type() )
+ {
+ case Symbol::Invalid:
+ out << "i";
+ break;
+ case Symbol::External:
+ out << "v";
+ break;
+ case Symbol::Slack:
+ out << "s";
+ break;
+ case Symbol::Error:
+ out << "e";
+ break;
+ case Symbol::Dummy:
+ out << "d";
+ break;
+ default:
+ break;
+ }
+ out << symbol.id();
+ }
+
+ static void dump( const Constraint& cn, std::ostream& out )
+ {
+ typedef std::vector<Term>::const_iterator iter_t;
+ iter_t begin = cn.expression().terms().begin();
+ iter_t end = cn.expression().terms().end();
+ for( iter_t it = begin; it != end; ++it )
+ {
+ out << it->coefficient() << " * ";
+ out << it->variable().name() << " + ";
+ }
+ out << cn.expression().constant();
+ switch( cn.op() )
+ {
+ case OP_LE:
+ out << " <= 0 ";
+ break;
+ case OP_GE:
+ out << " >= 0 ";
+ break;
+ case OP_EQ:
+ out << " == 0 ";
+ break;
+ default:
+ break;
+ }
+ out << " | strength = " << cn.strength() << std::endl;
+ }
+};
+
+} // namespace impl
+
+
+namespace debug
+{
+
+template<typename T>
+void dump( const T& value )
+{
+ impl::DebugHelper::dump( value, std::cout );
+}
+
+template<typename T>
+void dump( const T& value, std::ostream& out )
+{
+ impl::DebugHelper::dump( value, out );
+}
+
+template<typename T>
+std::string dumps( const T& value )
+{
+ std::stringstream stream;
+ impl::DebugHelper::dump( value, stream );
+ return stream.str();
+}
+
+} // namespace debug
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/errors.h b/contrib/python/kiwisolver/py3/kiwi/errors.h
new file mode 100644
index 00000000000..6c77eee0b70
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/errors.h
@@ -0,0 +1,188 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <exception>
+#include <string>
+#include "constraint.h"
+#include "variable.h"
+
+
+namespace kiwi
+{
+
+
+class UnsatisfiableConstraint : public std::exception
+{
+
+public:
+
+ UnsatisfiableConstraint( const Constraint& constraint ) :
+ m_constraint( constraint ) {}
+
+ ~UnsatisfiableConstraint() throw() {}
+
+ const char* what() const throw()
+ {
+ return "The constraint can not be satisfied.";
+ }
+
+ const Constraint& constraint() const
+ {
+ return m_constraint;
+ }
+
+private:
+
+ Constraint m_constraint;
+};
+
+
+class UnknownConstraint : public std::exception
+{
+
+public:
+
+ UnknownConstraint( const Constraint& constraint ) :
+ m_constraint( constraint ) {}
+
+ ~UnknownConstraint() throw() {}
+
+ const char* what() const throw()
+ {
+ return "The constraint has not been added to the solver.";
+ }
+
+ const Constraint& constraint() const
+ {
+ return m_constraint;
+ }
+
+private:
+
+ Constraint m_constraint;
+};
+
+
+class DuplicateConstraint : public std::exception
+{
+
+public:
+
+ DuplicateConstraint( const Constraint& constraint ) :
+ m_constraint( constraint ) {}
+
+ ~DuplicateConstraint() throw() {}
+
+ const char* what() const throw()
+ {
+ return "The constraint has already been added to the solver.";
+ }
+
+ const Constraint& constraint() const
+ {
+ return m_constraint;
+ }
+
+private:
+
+ Constraint m_constraint;
+};
+
+
+class UnknownEditVariable : public std::exception
+{
+
+public:
+
+ UnknownEditVariable( const Variable& variable ) :
+ m_variable( variable ) {}
+
+ ~UnknownEditVariable() throw() {}
+
+ const char* what() const throw()
+ {
+ return "The edit variable has not been added to the solver.";
+ }
+
+ const Variable& variable() const
+ {
+ return m_variable;
+ }
+
+private:
+
+ Variable m_variable;
+};
+
+
+class DuplicateEditVariable : public std::exception
+{
+
+public:
+
+ DuplicateEditVariable( const Variable& variable ) :
+ m_variable( variable ) {}
+
+ ~DuplicateEditVariable() throw() {}
+
+ const char* what() const throw()
+ {
+ return "The edit variable has already been added to the solver.";
+ }
+
+ const Variable& variable() const
+ {
+ return m_variable;
+ }
+
+private:
+
+ Variable m_variable;
+};
+
+
+class BadRequiredStrength : public std::exception
+{
+
+public:
+
+ BadRequiredStrength() {}
+
+ ~BadRequiredStrength() throw() {}
+
+ const char* what() const throw()
+ {
+ return "A required strength cannot be used in this context.";
+ }
+};
+
+
+class InternalSolverError : public std::exception
+{
+
+public:
+
+ InternalSolverError() : m_msg( "An internal solver error ocurred." ) {}
+
+ InternalSolverError( const char* msg ) : m_msg( msg ) {}
+
+ InternalSolverError( const std::string& msg ) : m_msg( msg ) {}
+
+ ~InternalSolverError() throw() {}
+
+ const char* what() const throw()
+ {
+ return m_msg.c_str();
+ }
+
+private:
+
+ std::string m_msg;
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/expression.h b/contrib/python/kiwisolver/py3/kiwi/expression.h
new file mode 100644
index 00000000000..6d757206bd7
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/expression.h
@@ -0,0 +1,57 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <vector>
+#include "term.h"
+
+
+namespace kiwi
+{
+
+class Expression
+{
+
+public:
+
+ Expression( double constant = 0.0 ) : m_constant( constant ) {}
+
+ Expression( const Term& term, double constant = 0.0 ) :
+ m_terms( 1, term ), m_constant( constant ) {}
+
+ Expression( const std::vector<Term>& terms, double constant = 0.0 ) :
+ m_terms( terms ), m_constant( constant ) {}
+
+ ~Expression() {}
+
+ const std::vector<Term>& terms() const
+ {
+ return m_terms;
+ }
+
+ double constant() const
+ {
+ return m_constant;
+ }
+
+ double value() const
+ {
+ typedef std::vector<Term>::const_iterator iter_t;
+ double result = m_constant;
+ iter_t end = m_terms.end();
+ for( iter_t it = m_terms.begin(); it != end; ++it )
+ result += it->value();
+ return result;
+ }
+
+private:
+
+ std::vector<Term> m_terms;
+ double m_constant;
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/kiwi.h b/contrib/python/kiwisolver/py3/kiwi/kiwi.h
new file mode 100644
index 00000000000..e5e3d85c90b
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/kiwi.h
@@ -0,0 +1,19 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include "constraint.h"
+#include "debug.h"
+#include "errors.h"
+#include "expression.h"
+#include "shareddata.h"
+#include "solver.h"
+#include "strength.h"
+#include "symbolics.h"
+#include "term.h"
+#include "variable.h"
+#include "version.h"
diff --git a/contrib/python/kiwisolver/py3/kiwi/maptype.h b/contrib/python/kiwisolver/py3/kiwi/maptype.h
new file mode 100644
index 00000000000..d125b07cc2d
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/maptype.h
@@ -0,0 +1,38 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <functional>
+#include <map>
+#include <memory>
+#include <utility>
+#include "AssocVector.h"
+
+
+namespace kiwi
+{
+
+namespace impl
+{
+
+template<
+ typename K,
+ typename V,
+ typename C = std::less<K>,
+ typename A = std::allocator< std::pair<K, V> > >
+class MapType
+{
+public:
+ typedef Loki::AssocVector<K, V, C, A> Type;
+ //typedef std::map<K, V, C, A> Type;
+private:
+ MapType();
+};
+
+} // namespace impl
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/row.h b/contrib/python/kiwisolver/py3/kiwi/row.h
new file mode 100644
index 00000000000..33b501df76c
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/row.h
@@ -0,0 +1,192 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include "maptype.h"
+#include "symbol.h"
+#include "util.h"
+
+
+namespace kiwi
+{
+
+namespace impl
+{
+
+class Row
+{
+
+public:
+
+ typedef MapType<Symbol, double>::Type CellMap;
+
+ Row() : m_constant( 0.0 ) {}
+
+ Row( double constant ) : m_constant( constant ) {}
+
+ Row( const Row& other ) :
+ m_cells( other.m_cells ), m_constant( other.m_constant ) {}
+
+ ~Row() {}
+
+ const CellMap& cells() const
+ {
+ return m_cells;
+ }
+
+ double constant() const
+ {
+ return m_constant;
+ }
+
+ /* Add a constant value to the row constant.
+
+ The new value of the constant is returned.
+
+ */
+ double add( double value )
+ {
+ return m_constant += value;
+ }
+
+ /* Insert a symbol into the row with a given coefficient.
+
+ If the symbol already exists in the row, the coefficient will be
+ added to the existing coefficient. If the resulting coefficient
+ is zero, the symbol will be removed from the row.
+
+ */
+ void insert( const Symbol& symbol, double coefficient = 1.0 )
+ {
+ if( nearZero( m_cells[ symbol ] += coefficient ) )
+ m_cells.erase( symbol );
+ }
+
+ /* Insert a row into this row with a given coefficient.
+
+ The constant and the cells of the other row will be multiplied by
+ the coefficient and added to this row. Any cell with a resulting
+ coefficient of zero will be removed from the row.
+
+ */
+ void insert( const Row& other, double coefficient = 1.0 )
+ {
+ typedef CellMap::const_iterator iter_t;
+ m_constant += other.m_constant * coefficient;
+ iter_t end = other.m_cells.end();
+ for( iter_t it = other.m_cells.begin(); it != end; ++it )
+ {
+ double coeff = it->second * coefficient;
+ if( nearZero( m_cells[ it->first ] += coeff ) )
+ m_cells.erase( it->first );
+ }
+ }
+
+ /* Remove the given symbol from the row.
+
+ */
+ void remove( const Symbol& symbol )
+ {
+ CellMap::iterator it = m_cells.find( symbol );
+ if( it != m_cells.end() )
+ m_cells.erase( it );
+ }
+
+ /* Reverse the sign of the constant and all cells in the row.
+
+ */
+ void reverseSign()
+ {
+ typedef CellMap::iterator iter_t;
+ m_constant = -m_constant;
+ iter_t end = m_cells.end();
+ for( iter_t it = m_cells.begin(); it != end; ++it )
+ it->second = -it->second;
+ }
+
+ /* Solve the row for the given symbol.
+
+ This method assumes the row is of the form a * x + b * y + c = 0
+ and (assuming solve for x) will modify the row to represent the
+ right hand side of x = -b/a * y - c / a. The target symbol will
+ be removed from the row, and the constant and other cells will
+ be multiplied by the negative inverse of the target coefficient.
+
+ The given symbol *must* exist in the row.
+
+ */
+ void solveFor( const Symbol& symbol )
+ {
+ typedef CellMap::iterator iter_t;
+ double coeff = -1.0 / m_cells[ symbol ];
+ m_cells.erase( symbol );
+ m_constant *= coeff;
+ iter_t end = m_cells.end();
+ for( iter_t it = m_cells.begin(); it != end; ++it )
+ it->second *= coeff;
+ }
+
+ /* Solve the row for the given symbols.
+
+ This method assumes the row is of the form x = b * y + c and will
+ solve the row such that y = x / b - c / b. The rhs symbol will be
+ removed from the row, the lhs added, and the result divided by the
+ negative inverse of the rhs coefficient.
+
+ The lhs symbol *must not* exist in the row, and the rhs symbol
+ *must* exist in the row.
+
+ */
+ void solveFor( const Symbol& lhs, const Symbol& rhs )
+ {
+ insert( lhs, -1.0 );
+ solveFor( rhs );
+ }
+
+ /* Get the coefficient for the given symbol.
+
+ If the symbol does not exist in the row, zero will be returned.
+
+ */
+ double coefficientFor( const Symbol& symbol ) const
+ {
+ CellMap::const_iterator it = m_cells.find( symbol );
+ if( it == m_cells.end() )
+ return 0.0;
+ return it->second;
+ }
+
+ /* Substitute a symbol with the data from another row.
+
+ Given a row of the form a * x + b and a substitution of the
+ form x = 3 * y + c the row will be updated to reflect the
+ expression 3 * a * y + a * c + b.
+
+ If the symbol does not exist in the row, this is a no-op.
+
+ */
+ void substitute( const Symbol& symbol, const Row& row )
+ {
+ typedef CellMap::iterator iter_t;
+ iter_t it = m_cells.find( symbol );
+ if( it != m_cells.end() )
+ {
+ double coefficient = it->second;
+ m_cells.erase( it );
+ insert( row, coefficient );
+ }
+ }
+
+private:
+
+ CellMap m_cells;
+ double m_constant;
+};
+
+} // namespace impl
+
+} // namespace
diff --git a/contrib/python/kiwisolver/py3/kiwi/shareddata.h b/contrib/python/kiwisolver/py3/kiwi/shareddata.h
new file mode 100644
index 00000000000..b7d389ee6dc
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/shareddata.h
@@ -0,0 +1,157 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+
+
+namespace kiwi
+{
+
+class SharedData
+{
+
+public:
+
+ SharedData() : m_refcount( 0 ) {}
+
+ SharedData( const SharedData& other ) : m_refcount( 0 ) {}
+
+ int m_refcount;
+
+private:
+
+ SharedData& operator=( const SharedData& other );
+};
+
+
+template<typename T>
+class SharedDataPtr
+{
+
+public:
+
+ typedef T Type;
+
+ SharedDataPtr() : m_data( 0 ) {}
+
+ explicit SharedDataPtr( T* data ) : m_data( data )
+ {
+ incref( m_data );
+ }
+
+ ~SharedDataPtr()
+ {
+ decref( m_data );
+ }
+
+ T* data()
+ {
+ return m_data;
+ }
+
+ const T* data() const
+ {
+ return m_data;
+ }
+
+ operator T*()
+ {
+ return m_data;
+ }
+
+ operator const T*() const
+ {
+ return m_data;
+ }
+
+ T* operator->()
+ {
+ return m_data;
+ }
+
+ const T* operator->() const
+ {
+ return m_data;
+ }
+
+ T& operator*()
+ {
+ return *m_data;
+ }
+
+ const T& operator*() const
+ {
+ return *m_data;
+ }
+
+ bool operator!() const
+ {
+ return !m_data;
+ }
+
+ bool operator<( const SharedDataPtr<T>& other ) const
+ {
+ return m_data < other.m_data;
+ }
+
+ bool operator==( const SharedDataPtr<T>& other ) const
+ {
+ return m_data == other.m_data;
+ }
+
+ bool operator!=( const SharedDataPtr<T>& other ) const
+ {
+ return m_data != other.m_data;
+ }
+
+ SharedDataPtr( const SharedDataPtr<T>& other ) : m_data( other.m_data )
+ {
+ incref( m_data );
+ }
+
+ SharedDataPtr<T>& operator=( const SharedDataPtr<T>& other )
+ {
+ if( m_data != other.m_data )
+ {
+ T* temp = m_data;
+ m_data = other.m_data;
+ incref( m_data );
+ decref( temp );
+ }
+ return *this;
+ }
+
+ SharedDataPtr<T>& operator=( T* other )
+ {
+ if( m_data != other )
+ {
+ T* temp = m_data;
+ m_data = other;
+ incref( m_data );
+ decref( temp );
+ }
+ return *this;
+ }
+
+private:
+
+ static void incref( T* data )
+ {
+ if( data )
+ ++data->m_refcount;
+ }
+
+ static void decref( T* data )
+ {
+ if( data && --data->m_refcount == 0 )
+ delete data;
+ }
+
+ T* m_data;
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/solver.h b/contrib/python/kiwisolver/py3/kiwi/solver.h
new file mode 100644
index 00000000000..8eed1841bf9
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/solver.h
@@ -0,0 +1,178 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include "constraint.h"
+#include "debug.h"
+#include "solverimpl.h"
+#include "strength.h"
+#include "variable.h"
+
+
+namespace kiwi
+{
+
+class Solver
+{
+
+public:
+
+ Solver() {}
+
+ ~Solver() {}
+
+ /* Add a constraint to the solver.
+
+ Throws
+ ------
+ DuplicateConstraint
+ The given constraint has already been added to the solver.
+
+ UnsatisfiableConstraint
+ The given constraint is required and cannot be satisfied.
+
+ */
+ void addConstraint( const Constraint& constraint )
+ {
+ m_impl.addConstraint( constraint );
+ }
+
+ /* Remove a constraint from the solver.
+
+ Throws
+ ------
+ UnknownConstraint
+ The given constraint has not been added to the solver.
+
+ */
+ void removeConstraint( const Constraint& constraint )
+ {
+ m_impl.removeConstraint( constraint );
+ }
+
+ /* Test whether a constraint has been added to the solver.
+
+ */
+ bool hasConstraint( const Constraint& constraint ) const
+ {
+ return m_impl.hasConstraint( constraint );
+ }
+
+ /* Add an edit variable to the solver.
+
+ This method should be called before the `suggestValue` method is
+ used to supply a suggested value for the given edit variable.
+
+ Throws
+ ------
+ DuplicateEditVariable
+ The given edit variable has already been added to the solver.
+
+ BadRequiredStrength
+ The given strength is >= required.
+
+ */
+ void addEditVariable( const Variable& variable, double strength )
+ {
+ m_impl.addEditVariable( variable, strength );
+ }
+
+ /* Remove an edit variable from the solver.
+
+ Throws
+ ------
+ UnknownEditVariable
+ The given edit variable has not been added to the solver.
+
+ */
+ void removeEditVariable( const Variable& variable )
+ {
+ m_impl.removeEditVariable( variable );
+ }
+
+ /* Test whether an edit variable has been added to the solver.
+
+ */
+ bool hasEditVariable( const Variable& variable ) const
+ {
+ return m_impl.hasEditVariable( variable );
+ }
+
+ /* Suggest a value for the given edit variable.
+
+ This method should be used after an edit variable as been added to
+ the solver in order to suggest the value for that variable. After
+ all suggestions have been made, the `solve` method can be used to
+ update the values of all variables.
+
+ Throws
+ ------
+ UnknownEditVariable
+ The given edit variable has not been added to the solver.
+
+ */
+ void suggestValue( const Variable& variable, double value )
+ {
+ m_impl.suggestValue( variable, value );
+ }
+
+ /* Update the values of the external solver variables.
+
+ */
+ void updateVariables()
+ {
+ m_impl.updateVariables();
+ }
+
+ /* Reset the solver to the empty starting condition.
+
+ This method resets the internal solver state to the empty starting
+ condition, as if no constraints or edit variables have been added.
+ This can be faster than deleting the solver and creating a new one
+ when the entire system must change, since it can avoid unecessary
+ heap (de)allocations.
+
+ */
+ void reset()
+ {
+ m_impl.reset();
+ }
+
+ /* Dump a representation of the solver internals to stdout.
+
+ */
+ void dump()
+ {
+ debug::dump( m_impl );
+ }
+
+ /* Dump a representation of the solver internals to a stream.
+
+ */
+ void dump( std::ostream& out )
+ {
+ debug::dump( m_impl, out );
+ }
+
+ /* Dump a representation of the solver internals to a string.
+
+ */
+ std::string dumps()
+ {
+ return debug::dumps( m_impl );
+ }
+
+private:
+
+ Solver( const Solver& );
+
+ Solver& operator=( const Solver& );
+
+ impl::SolverImpl m_impl;
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/solverimpl.h b/contrib/python/kiwisolver/py3/kiwi/solverimpl.h
new file mode 100644
index 00000000000..9b56ee28188
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/solverimpl.h
@@ -0,0 +1,840 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <vector>
+#include "constraint.h"
+#include "errors.h"
+#include "expression.h"
+#include "maptype.h"
+#include "row.h"
+#include "symbol.h"
+#include "term.h"
+#include "util.h"
+#include "variable.h"
+
+
+namespace kiwi
+{
+
+namespace impl
+{
+
+class SolverImpl
+{
+ friend class DebugHelper;
+
+ struct Tag
+ {
+ Symbol marker;
+ Symbol other;
+ };
+
+ struct EditInfo
+ {
+ Tag tag;
+ Constraint constraint;
+ double constant;
+ };
+
+ typedef MapType<Variable, Symbol>::Type VarMap;
+
+ typedef MapType<Symbol, Row*>::Type RowMap;
+
+ typedef MapType<Constraint, Tag>::Type CnMap;
+
+ typedef MapType<Variable, EditInfo>::Type EditMap;
+
+ struct DualOptimizeGuard
+ {
+ DualOptimizeGuard( SolverImpl& impl ) : m_impl( impl ) {}
+ ~DualOptimizeGuard() { m_impl.dualOptimize(); }
+ SolverImpl& m_impl;
+ };
+
+public:
+
+ SolverImpl() : m_objective( new Row() ), m_id_tick( 1 ) {}
+
+ ~SolverImpl() { clearRows(); }
+
+ /* Add a constraint to the solver.
+
+ Throws
+ ------
+ DuplicateConstraint
+ The given constraint has already been added to the solver.
+
+ UnsatisfiableConstraint
+ The given constraint is required and cannot be satisfied.
+
+ */
+ void addConstraint( const Constraint& constraint )
+ {
+ if( m_cns.find( constraint ) != m_cns.end() )
+ throw DuplicateConstraint( constraint );
+
+ // Creating a row causes symbols to be reserved for the variables
+ // in the constraint. If this method exits with an exception,
+ // then its possible those variables will linger in the var map.
+ // Since its likely that those variables will be used in other
+ // constraints and since exceptional conditions are uncommon,
+ // i'm not too worried about aggressive cleanup of the var map.
+ Tag tag;
+ std::auto_ptr<Row> rowptr( createRow( constraint, tag ) );
+ Symbol subject( chooseSubject( *rowptr, tag ) );
+
+ // If chooseSubject could not find a valid entering symbol, one
+ // last option is available if the entire row is composed of
+ // dummy variables. If the constant of the row is zero, then
+ // this represents redundant constraints and the new dummy
+ // marker can enter the basis. If the constant is non-zero,
+ // then it represents an unsatisfiable constraint.
+ if( subject.type() == Symbol::Invalid && allDummies( *rowptr ) )
+ {
+ if( !nearZero( rowptr->constant() ) )
+ throw UnsatisfiableConstraint( constraint );
+ else
+ subject = tag.marker;
+ }
+
+ // If an entering symbol still isn't found, then the row must
+ // be added using an artificial variable. If that fails, then
+ // the row represents an unsatisfiable constraint.
+ if( subject.type() == Symbol::Invalid )
+ {
+ if( !addWithArtificialVariable( *rowptr ) )
+ throw UnsatisfiableConstraint( constraint );
+ }
+ else
+ {
+ rowptr->solveFor( subject );
+ substitute( subject, *rowptr );
+ m_rows[ subject ] = rowptr.release();
+ }
+
+ m_cns[ constraint ] = tag;
+
+ // Optimizing after each constraint is added performs less
+ // aggregate work due to a smaller average system size. It
+ // also ensures the solver remains in a consistent state.
+ optimize( *m_objective );
+ }
+
+ /* Remove a constraint from the solver.
+
+ Throws
+ ------
+ UnknownConstraint
+ The given constraint has not been added to the solver.
+
+ */
+ void removeConstraint( const Constraint& constraint )
+ {
+ CnMap::iterator cn_it = m_cns.find( constraint );
+ if( cn_it == m_cns.end() )
+ throw UnknownConstraint( constraint );
+
+ Tag tag( cn_it->second );
+ m_cns.erase( cn_it );
+
+ // Remove the error effects from the objective function
+ // *before* pivoting, or substitutions into the objective
+ // will lead to incorrect solver results.
+ removeConstraintEffects( constraint, tag );
+
+ // If the marker is basic, simply drop the row. Otherwise,
+ // pivot the marker into the basis and then drop the row.
+ RowMap::iterator row_it = m_rows.find( tag.marker );
+ if( row_it != m_rows.end() )
+ {
+ std::auto_ptr<Row> rowptr( row_it->second );
+ m_rows.erase( row_it );
+ }
+ else
+ {
+ row_it = getMarkerLeavingRow( tag.marker );
+ if( row_it == m_rows.end() )
+ throw InternalSolverError( "failed to find leaving row" );
+ Symbol leaving( row_it->first );
+ std::auto_ptr<Row> rowptr( row_it->second );
+ m_rows.erase( row_it );
+ rowptr->solveFor( leaving, tag.marker );
+ substitute( tag.marker, *rowptr );
+ }
+
+ // Optimizing after each constraint is removed ensures that the
+ // solver remains consistent. It makes the solver api easier to
+ // use at a small tradeoff for speed.
+ optimize( *m_objective );
+ }
+
+ /* Test whether a constraint has been added to the solver.
+
+ */
+ bool hasConstraint( const Constraint& constraint ) const
+ {
+ return m_cns.find( constraint ) != m_cns.end();
+ }
+
+ /* Add an edit variable to the solver.
+
+ This method should be called before the `suggestValue` method is
+ used to supply a suggested value for the given edit variable.
+
+ Throws
+ ------
+ DuplicateEditVariable
+ The given edit variable has already been added to the solver.
+
+ BadRequiredStrength
+ The given strength is >= required.
+
+ */
+ void addEditVariable( const Variable& variable, double strength )
+ {
+ if( m_edits.find( variable ) != m_edits.end() )
+ throw DuplicateEditVariable( variable );
+ strength = strength::clip( strength );
+ if( strength == strength::required )
+ throw BadRequiredStrength();
+ Constraint cn( Expression( variable ), OP_EQ, strength );
+ addConstraint( cn );
+ EditInfo info;
+ info.tag = m_cns[ cn ];
+ info.constraint = cn;
+ info.constant = 0.0;
+ m_edits[ variable ] = info;
+ }
+
+ /* Remove an edit variable from the solver.
+
+ Throws
+ ------
+ UnknownEditVariable
+ The given edit variable has not been added to the solver.
+
+ */
+ void removeEditVariable( const Variable& variable )
+ {
+ EditMap::iterator it = m_edits.find( variable );
+ if( it == m_edits.end() )
+ throw UnknownEditVariable( variable );
+ removeConstraint( it->second.constraint );
+ m_edits.erase( it );
+ }
+
+ /* Test whether an edit variable has been added to the solver.
+
+ */
+ bool hasEditVariable( const Variable& variable ) const
+ {
+ return m_edits.find( variable ) != m_edits.end();
+ }
+
+ /* Suggest a value for the given edit variable.
+
+ This method should be used after an edit variable as been added to
+ the solver in order to suggest the value for that variable.
+
+ Throws
+ ------
+ UnknownEditVariable
+ The given edit variable has not been added to the solver.
+
+ */
+ void suggestValue( const Variable& variable, double value )
+ {
+ EditMap::iterator it = m_edits.find( variable );
+ if( it == m_edits.end() )
+ throw UnknownEditVariable( variable );
+
+ DualOptimizeGuard guard( *this );
+ EditInfo& info = it->second;
+ double delta = value - info.constant;
+ info.constant = value;
+
+ // Check first if the positive error variable is basic.
+ RowMap::iterator row_it = m_rows.find( info.tag.marker );
+ if( row_it != m_rows.end() )
+ {
+ if( row_it->second->add( -delta ) < 0.0 )
+ m_infeasible_rows.push_back( row_it->first );
+ return;
+ }
+
+ // Check next if the negative error variable is basic.
+ row_it = m_rows.find( info.tag.other );
+ if( row_it != m_rows.end() )
+ {
+ if( row_it->second->add( delta ) < 0.0 )
+ m_infeasible_rows.push_back( row_it->first );
+ return;
+ }
+
+ // Otherwise update each row where the error variables exist.
+ RowMap::iterator end = m_rows.end();
+ for( row_it = m_rows.begin(); row_it != end; ++row_it )
+ {
+ double coeff = row_it->second->coefficientFor( info.tag.marker );
+ if( coeff != 0.0 &&
+ row_it->second->add( delta * coeff ) < 0.0 &&
+ row_it->first.type() != Symbol::External )
+ m_infeasible_rows.push_back( row_it->first );
+ }
+ }
+
+ /* Update the values of the external solver variables.
+
+ */
+ void updateVariables()
+ {
+ typedef RowMap::iterator row_iter_t;
+ typedef VarMap::iterator var_iter_t;
+ row_iter_t row_end = m_rows.end();
+ var_iter_t var_end = m_vars.end();
+ for( var_iter_t var_it = m_vars.begin(); var_it != var_end; ++var_it )
+ {
+ Variable& var( const_cast<Variable&>( var_it->first ) );
+ row_iter_t row_it = m_rows.find( var_it->second );
+ if( row_it == row_end )
+ var.setValue( 0.0 );
+ else
+ var.setValue( row_it->second->constant() );
+ }
+ }
+
+ /* Reset the solver to the empty starting condition.
+
+ This method resets the internal solver state to the empty starting
+ condition, as if no constraints or edit variables have been added.
+ This can be faster than deleting the solver and creating a new one
+ when the entire system must change, since it can avoid unecessary
+ heap (de)allocations.
+
+ */
+ void reset()
+ {
+ clearRows();
+ m_cns.clear();
+ m_vars.clear();
+ m_edits.clear();
+ m_infeasible_rows.clear();
+ m_objective.reset( new Row() );
+ m_artificial.reset();
+ m_id_tick = 1;
+ }
+
+private:
+
+ SolverImpl( const SolverImpl& );
+
+ SolverImpl& operator=( const SolverImpl& );
+
+ struct RowDeleter
+ {
+ template<typename T>
+ void operator()( T& pair ) { delete pair.second; }
+ };
+
+ void clearRows()
+ {
+ std::for_each( m_rows.begin(), m_rows.end(), RowDeleter() );
+ m_rows.clear();
+ }
+
+ /* Get the symbol for the given variable.
+
+ If a symbol does not exist for the variable, one will be created.
+
+ */
+ Symbol getVarSymbol( const Variable& variable )
+ {
+ VarMap::iterator it = m_vars.find( variable );
+ if( it != m_vars.end() )
+ return it->second;
+ Symbol symbol( Symbol::External, m_id_tick++ );
+ m_vars[ variable ] = symbol;
+ return symbol;
+ }
+
+ /* Create a new Row object for the given constraint.
+
+ The terms in the constraint will be converted to cells in the row.
+ Any term in the constraint with a coefficient of zero is ignored.
+ This method uses the `getVarSymbol` method to get the symbol for
+ the variables added to the row. If the symbol for a given cell
+ variable is basic, the cell variable will be substituted with the
+ basic row.
+
+ The necessary slack and error variables will be added to the row.
+ If the constant for the row is negative, the sign for the row
+ will be inverted so the constant becomes positive.
+
+ The tag will be updated with the marker and error symbols to use
+ for tracking the movement of the constraint in the tableau.
+
+ */
+ Row* createRow( const Constraint& constraint, Tag& tag )
+ {
+ typedef std::vector<Term>::const_iterator iter_t;
+ const Expression& expr( constraint.expression() );
+ Row* row = new Row( expr.constant() );
+
+ // Substitute the current basic variables into the row.
+ iter_t end = expr.terms().end();
+ for( iter_t it = expr.terms().begin(); it != end; ++it )
+ {
+ if( !nearZero( it->coefficient() ) )
+ {
+ Symbol symbol( getVarSymbol( it->variable() ) );
+ RowMap::const_iterator row_it = m_rows.find( symbol );
+ if( row_it != m_rows.end() )
+ row->insert( *row_it->second, it->coefficient() );
+ else
+ row->insert( symbol, it->coefficient() );
+ }
+ }
+
+ // Add the necessary slack, error, and dummy variables.
+ switch( constraint.op() )
+ {
+ case OP_LE:
+ case OP_GE:
+ {
+ double coeff = constraint.op() == OP_LE ? 1.0 : -1.0;
+ Symbol slack( Symbol::Slack, m_id_tick++ );
+ tag.marker = slack;
+ row->insert( slack, coeff );
+ if( constraint.strength() < strength::required )
+ {
+ Symbol error( Symbol::Error, m_id_tick++ );
+ tag.other = error;
+ row->insert( error, -coeff );
+ m_objective->insert( error, constraint.strength() );
+ }
+ break;
+ }
+ case OP_EQ:
+ {
+ if( constraint.strength() < strength::required )
+ {
+ Symbol errplus( Symbol::Error, m_id_tick++ );
+ Symbol errminus( Symbol::Error, m_id_tick++ );
+ tag.marker = errplus;
+ tag.other = errminus;
+ row->insert( errplus, -1.0 ); // v = eplus - eminus
+ row->insert( errminus, 1.0 ); // v - eplus + eminus = 0
+ m_objective->insert( errplus, constraint.strength() );
+ m_objective->insert( errminus, constraint.strength() );
+ }
+ else
+ {
+ Symbol dummy( Symbol::Dummy, m_id_tick++ );
+ tag.marker = dummy;
+ row->insert( dummy );
+ }
+ break;
+ }
+ }
+
+ // Ensure the row as a positive constant.
+ if( row->constant() < 0.0 )
+ row->reverseSign();
+
+ return row;
+ }
+
+ /* Choose the subject for solving for the row.
+
+ This method will choose the best subject for using as the solve
+ target for the row. An invalid symbol will be returned if there
+ is no valid target.
+
+ The symbols are chosen according to the following precedence:
+
+ 1) The first symbol representing an external variable.
+ 2) A negative slack or error tag variable.
+
+ If a subject cannot be found, an invalid symbol will be returned.
+
+ */
+ Symbol chooseSubject( const Row& row, const Tag& tag )
+ {
+ typedef Row::CellMap::const_iterator iter_t;
+ iter_t end = row.cells().end();
+ for( iter_t it = row.cells().begin(); it != end; ++it )
+ {
+ if( it->first.type() == Symbol::External )
+ return it->first;
+ }
+ if( tag.marker.type() == Symbol::Slack || tag.marker.type() == Symbol::Error )
+ {
+ if( row.coefficientFor( tag.marker ) < 0.0 )
+ return tag.marker;
+ }
+ if( tag.other.type() == Symbol::Slack || tag.other.type() == Symbol::Error )
+ {
+ if( row.coefficientFor( tag.other ) < 0.0 )
+ return tag.other;
+ }
+ return Symbol();
+ }
+
+ /* Add the row to the tableau using an artificial variable.
+
+ This will return false if the constraint cannot be satisfied.
+
+ */
+ bool addWithArtificialVariable( const Row& row )
+ {
+ // Create and add the artificial variable to the tableau
+ Symbol art( Symbol::Slack, m_id_tick++ );
+ m_rows[ art ] = new Row( row );
+ m_artificial.reset( new Row( row ) );
+
+ // Optimize the artificial objective. This is successful
+ // only if the artificial objective is optimized to zero.
+ optimize( *m_artificial );
+ bool success = nearZero( m_artificial->constant() );
+ m_artificial.reset();
+
+ // If the artificial variable is not basic, pivot the row so that
+ // it becomes basic. If the row is constant, exit early.
+ RowMap::iterator it = m_rows.find( art );
+ if( it != m_rows.end() )
+ {
+ std::auto_ptr<Row> rowptr( it->second );
+ m_rows.erase( it );
+ if( rowptr->cells().empty() )
+ return success;
+ Symbol entering( anyPivotableSymbol( *rowptr ) );
+ if( entering.type() == Symbol::Invalid )
+ return false; // unsatisfiable (will this ever happen?)
+ rowptr->solveFor( art, entering );
+ substitute( entering, *rowptr );
+ m_rows[ entering ] = rowptr.release();
+ }
+
+ // Remove the artificial variable from the tableau.
+ RowMap::iterator end = m_rows.end();
+ for( it = m_rows.begin(); it != end; ++it )
+ it->second->remove( art );
+ m_objective->remove( art );
+ return success;
+ }
+
+ /* Substitute the parametric symbol with the given row.
+
+ This method will substitute all instances of the parametric symbol
+ in the tableau and the objective function with the given row.
+
+ */
+ void substitute( const Symbol& symbol, const Row& row )
+ {
+ typedef RowMap::iterator iter_t;
+ iter_t end = m_rows.end();
+ for( iter_t it = m_rows.begin(); it != end; ++it )
+ {
+ it->second->substitute( symbol, row );
+ if( it->first.type() != Symbol::External &&
+ it->second->constant() < 0.0 )
+ m_infeasible_rows.push_back( it->first );
+ }
+ m_objective->substitute( symbol, row );
+ if( m_artificial.get() )
+ m_artificial->substitute( symbol, row );
+ }
+
+ /* Optimize the system for the given objective function.
+
+ This method performs iterations of Phase 2 of the simplex method
+ until the objective function reaches a minimum.
+
+ Throws
+ ------
+ InternalSolverError
+ The value of the objective function is unbounded.
+
+ */
+ void optimize( const Row& objective )
+ {
+ while( true )
+ {
+ Symbol entering( getEnteringSymbol( objective ) );
+ if( entering.type() == Symbol::Invalid )
+ return;
+ RowMap::iterator it = getLeavingRow( entering );
+ if( it == m_rows.end() )
+ throw InternalSolverError( "The objective is unbounded." );
+ // pivot the entering symbol into the basis
+ Symbol leaving( it->first );
+ Row* row = it->second;
+ m_rows.erase( it );
+ row->solveFor( leaving, entering );
+ substitute( entering, *row );
+ m_rows[ entering ] = row;
+ }
+ }
+
+ /* Optimize the system using the dual of the simplex method.
+
+ The current state of the system should be such that the objective
+ function is optimal, but not feasible. This method will perform
+ an iteration of the dual simplex method to make the solution both
+ optimal and feasible.
+
+ Throws
+ ------
+ InternalSolverError
+ The system cannot be dual optimized.
+
+ */
+ void dualOptimize()
+ {
+ while( !m_infeasible_rows.empty() )
+ {
+
+ Symbol leaving( m_infeasible_rows.back() );
+ m_infeasible_rows.pop_back();
+ RowMap::iterator it = m_rows.find( leaving );
+ if( it != m_rows.end() && !nearZero( it->second->constant() ) &&
+ it->second->constant() < 0.0 )
+ {
+ Symbol entering( getDualEnteringSymbol( *it->second ) );
+ if( entering.type() == Symbol::Invalid )
+ throw InternalSolverError( "Dual optimize failed." );
+ // pivot the entering symbol into the basis
+ Row* row = it->second;
+ m_rows.erase( it );
+ row->solveFor( leaving, entering );
+ substitute( entering, *row );
+ m_rows[ entering ] = row;
+ }
+ }
+ }
+
+ /* Compute the entering variable for a pivot operation.
+
+ This method will return first symbol in the objective function which
+ is non-dummy and has a coefficient less than zero. If no symbol meets
+ the criteria, it means the objective function is at a minimum, and an
+ invalid symbol is returned.
+
+ */
+ Symbol getEnteringSymbol( const Row& objective )
+ {
+ typedef Row::CellMap::const_iterator iter_t;
+ iter_t end = objective.cells().end();
+ for( iter_t it = objective.cells().begin(); it != end; ++it )
+ {
+ if( it->first.type() != Symbol::Dummy && it->second < 0.0 )
+ return it->first;
+ }
+ return Symbol();
+ }
+
+ /* Compute the entering symbol for the dual optimize operation.
+
+ This method will return the symbol in the row which has a positive
+ coefficient and yields the minimum ratio for its respective symbol
+ in the objective function. The provided row *must* be infeasible.
+ If no symbol is found which meats the criteria, an invalid symbol
+ is returned.
+
+ */
+ Symbol getDualEnteringSymbol( const Row& row )
+ {
+ typedef Row::CellMap::const_iterator iter_t;
+ Symbol entering;
+ double ratio = std::numeric_limits<double>::max();
+ iter_t end = row.cells().end();
+ for( iter_t it = row.cells().begin(); it != end; ++it )
+ {
+ if( it->second > 0.0 && it->first.type() != Symbol::Dummy )
+ {
+ double coeff = m_objective->coefficientFor( it->first );
+ double r = coeff / it->second;
+ if( r < ratio )
+ {
+ ratio = r;
+ entering = it->first;
+ }
+ }
+ }
+ return entering;
+ }
+
+ /* Get the first Slack or Error symbol in the row.
+
+ If no such symbol is present, and Invalid symbol will be returned.
+
+ */
+ Symbol anyPivotableSymbol( const Row& row )
+ {
+ typedef Row::CellMap::const_iterator iter_t;
+ iter_t end = row.cells().end();
+ for( iter_t it = row.cells().begin(); it != end; ++it )
+ {
+ const Symbol& sym( it->first );
+ if( sym.type() == Symbol::Slack || sym.type() == Symbol::Error )
+ return sym;
+ }
+ return Symbol();
+ }
+
+ /* Compute the row which holds the exit symbol for a pivot.
+
+ This method will return an iterator to the row in the row map
+ which holds the exit symbol. If no appropriate exit symbol is
+ found, the end() iterator will be returned. This indicates that
+ the objective function is unbounded.
+
+ */
+ RowMap::iterator getLeavingRow( const Symbol& entering )
+ {
+ typedef RowMap::iterator iter_t;
+ double ratio = std::numeric_limits<double>::max();
+ iter_t end = m_rows.end();
+ iter_t found = m_rows.end();
+ for( iter_t it = m_rows.begin(); it != end; ++it )
+ {
+ if( it->first.type() != Symbol::External )
+ {
+ double temp = it->second->coefficientFor( entering );
+ if( temp < 0.0 )
+ {
+ double temp_ratio = -it->second->constant() / temp;
+ if( temp_ratio < ratio )
+ {
+ ratio = temp_ratio;
+ found = it;
+ }
+ }
+ }
+ }
+ return found;
+ }
+
+ /* Compute the leaving row for a marker variable.
+
+ This method will return an iterator to the row in the row map
+ which holds the given marker variable. The row will be chosen
+ according to the following precedence:
+
+ 1) The row with a restricted basic varible and a negative coefficient
+ for the marker with the smallest ratio of -constant / coefficient.
+
+ 2) The row with a restricted basic variable and the smallest ratio
+ of constant / coefficient.
+
+ 3) The last unrestricted row which contains the marker.
+
+ If the marker does not exist in any row, the row map end() iterator
+ will be returned. This indicates an internal solver error since
+ the marker *should* exist somewhere in the tableau.
+
+ */
+ RowMap::iterator getMarkerLeavingRow( const Symbol& marker )
+ {
+ const double dmax = std::numeric_limits<double>::max();
+ typedef RowMap::iterator iter_t;
+ double r1 = dmax;
+ double r2 = dmax;
+ iter_t end = m_rows.end();
+ iter_t first = end;
+ iter_t second = end;
+ iter_t third = end;
+ for( iter_t it = m_rows.begin(); it != end; ++it )
+ {
+ double c = it->second->coefficientFor( marker );
+ if( c == 0.0 )
+ continue;
+ if( it->first.type() == Symbol::External )
+ {
+ third = it;
+ }
+ else if( c < 0.0 )
+ {
+ double r = -it->second->constant() / c;
+ if( r < r1 )
+ {
+ r1 = r;
+ first = it;
+ }
+ }
+ else
+ {
+ double r = it->second->constant() / c;
+ if( r < r2 )
+ {
+ r2 = r;
+ second = it;
+ }
+ }
+ }
+ if( first != end )
+ return first;
+ if( second != end )
+ return second;
+ return third;
+ }
+
+ /* Remove the effects of a constraint on the objective function.
+
+ */
+ void removeConstraintEffects( const Constraint& cn, const Tag& tag )
+ {
+ if( tag.marker.type() == Symbol::Error )
+ removeMarkerEffects( tag.marker, cn.strength() );
+ if( tag.other.type() == Symbol::Error )
+ removeMarkerEffects( tag.other, cn.strength() );
+ }
+
+ /* Remove the effects of an error marker on the objective function.
+
+ */
+ void removeMarkerEffects( const Symbol& marker, double strength )
+ {
+ RowMap::iterator row_it = m_rows.find( marker );
+ if( row_it != m_rows.end() )
+ m_objective->insert( *row_it->second, -strength );
+ else
+ m_objective->insert( marker, -strength );
+ }
+
+ /* Test whether a row is composed of all dummy variables.
+
+ */
+ bool allDummies( const Row& row )
+ {
+ typedef Row::CellMap::const_iterator iter_t;
+ iter_t end = row.cells().end();
+ for( iter_t it = row.cells().begin(); it != end; ++it )
+ {
+ if( it->first.type() != Symbol::Dummy )
+ return false;
+ }
+ return true;
+ }
+
+ CnMap m_cns;
+ RowMap m_rows;
+ VarMap m_vars;
+ EditMap m_edits;
+ std::vector<Symbol> m_infeasible_rows;
+ std::auto_ptr<Row> m_objective;
+ std::auto_ptr<Row> m_artificial;
+ Symbol::Id m_id_tick;
+};
+
+} // namespace impl
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/strength.h b/contrib/python/kiwisolver/py3/kiwi/strength.h
new file mode 100644
index 00000000000..b077f3e17c1
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/strength.h
@@ -0,0 +1,44 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <algorithm>
+
+
+namespace kiwi
+{
+
+namespace strength
+{
+
+inline double create( double a, double b, double c, double w = 1.0 )
+{
+ double result = 0.0;
+ result += std::max( 0.0, std::min( 1000.0, a * w ) ) * 1000000.0;
+ result += std::max( 0.0, std::min( 1000.0, b * w ) ) * 1000.0;
+ result += std::max( 0.0, std::min( 1000.0, c * w ) );
+ return result;
+}
+
+
+const double required = create( 1000.0, 1000.0, 1000.0 );
+
+const double strong = create( 1.0, 0.0, 0.0 );
+
+const double medium = create( 0.0, 1.0, 0.0 );
+
+const double weak = create( 0.0, 0.0, 1.0 );
+
+
+inline double clip( double value )
+{
+ return std::max( 0.0, std::min( required, value ) );
+}
+
+} // namespace strength
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/symbol.h b/contrib/python/kiwisolver/py3/kiwi/symbol.h
new file mode 100644
index 00000000000..b971efbdd25
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/symbol.h
@@ -0,0 +1,68 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+
+
+namespace kiwi
+{
+
+namespace impl
+{
+
+class Symbol
+{
+
+public:
+
+ typedef unsigned long long Id;
+
+ enum Type
+ {
+ Invalid,
+ External,
+ Slack,
+ Error,
+ Dummy
+ };
+
+ Symbol() : m_id( 0 ), m_type( Invalid ) {}
+
+ Symbol( Type type, Id id ) : m_id( id ), m_type( type ) {}
+
+ ~Symbol() {}
+
+ Id id() const
+ {
+ return m_id;
+ }
+
+ Type type() const
+ {
+ return m_type;
+ }
+
+private:
+
+ Id m_id;
+ Type m_type;
+
+ friend bool operator<( const Symbol& lhs, const Symbol& rhs )
+ {
+ return lhs.m_id < rhs.m_id;
+ }
+
+ friend bool operator==( const Symbol& lhs, const Symbol& rhs )
+ {
+ return lhs.m_id == rhs.m_id;
+ }
+
+};
+
+} // namespace impl
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/symbolics.h b/contrib/python/kiwisolver/py3/kiwi/symbolics.h
new file mode 100644
index 00000000000..51ac6a8a37b
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/symbolics.h
@@ -0,0 +1,685 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <vector>
+#include "constraint.h"
+#include "expression.h"
+#include "term.h"
+#include "variable.h"
+
+
+namespace kiwi
+{
+
+// Variable multiply, divide, and unary invert
+
+inline
+Term operator*( const Variable& variable, double coefficient )
+{
+ return Term( variable, coefficient );
+}
+
+
+inline
+Term operator/( const Variable& variable, double denominator )
+{
+ return variable * ( 1.0 / denominator );
+}
+
+
+inline
+Term operator-( const Variable& variable )
+{
+ return variable * -1.0;
+}
+
+
+// Term multiply, divide, and unary invert
+
+inline
+Term operator*( const Term& term, double coefficient )
+{
+ return Term( term.variable(), term.coefficient() * coefficient );
+}
+
+
+inline
+Term operator/( const Term& term, double denominator )
+{
+ return term * ( 1.0 / denominator );
+}
+
+
+inline
+Term operator-( const Term& term )
+{
+ return term * -1.0;
+}
+
+
+// Expression multiply, divide, and unary invert
+
+inline
+Expression operator*( const Expression& expression, double coefficient )
+{
+ std::vector<Term> terms;
+ terms.reserve( expression.terms().size() );
+ typedef std::vector<Term>::const_iterator iter_t;
+ iter_t begin = expression.terms().begin();
+ iter_t end = expression.terms().end();
+ for( iter_t it = begin; it != end; ++it )
+ terms.push_back( ( *it ) * coefficient );
+ return Expression( terms, expression.constant() * coefficient );
+}
+
+
+inline
+Expression operator/( const Expression& expression, double denominator )
+{
+ return expression * ( 1.0 / denominator );
+}
+
+
+inline
+Expression operator-( const Expression& expression )
+{
+ return expression * -1.0;
+}
+
+
+// Double multiply
+
+inline
+Expression operator*( double coefficient, const Expression& expression )
+{
+ return expression * coefficient;
+}
+
+
+inline
+Term operator*( double coefficient, const Term& term )
+{
+ return term * coefficient;
+}
+
+
+inline
+Term operator*( double coefficient, const Variable& variable )
+{
+ return variable * coefficient;
+}
+
+
+// Expression add and subtract
+
+inline
+Expression operator+( const Expression& first, const Expression& second )
+{
+ std::vector<Term> terms;
+ terms.reserve( first.terms().size() + second.terms().size() );
+ terms.insert( terms.begin(), first.terms().begin(), first.terms().end() );
+ terms.insert( terms.end(), second.terms().begin(), second.terms().end() );
+ return Expression( terms, first.constant() + second.constant() );
+}
+
+
+inline
+Expression operator+( const Expression& first, const Term& second )
+{
+ std::vector<Term> terms;
+ terms.reserve( first.terms().size() + 1 );
+ terms.insert( terms.begin(), first.terms().begin(), first.terms().end() );
+ terms.push_back( second );
+ return Expression( terms, first.constant() );
+}
+
+
+inline
+Expression operator+( const Expression& expression, const Variable& variable )
+{
+ return expression + Term( variable );
+}
+
+
+inline
+Expression operator+( const Expression& expression, double constant )
+{
+ return Expression( expression.terms(), expression.constant() + constant );
+}
+
+
+inline
+Expression operator-( const Expression& first, const Expression& second )
+{
+ return first + -second;
+}
+
+
+inline
+Expression operator-( const Expression& expression, const Term& term )
+{
+ return expression + -term;
+}
+
+
+inline
+Expression operator-( const Expression& expression, const Variable& variable )
+{
+ return expression + -variable;
+}
+
+
+inline
+Expression operator-( const Expression& expression, double constant )
+{
+ return expression + -constant;
+}
+
+
+// Term add and subtract
+
+inline
+Expression operator+( const Term& term, const Expression& expression )
+{
+ return expression + term;
+}
+
+
+inline
+Expression operator+( const Term& first, const Term& second )
+{
+ std::vector<Term> terms;
+ terms.reserve( 2 );
+ terms.push_back( first );
+ terms.push_back( second );
+ return Expression( terms );
+}
+
+
+inline
+Expression operator+( const Term& term, const Variable& variable )
+{
+ return term + Term( variable );
+}
+
+
+inline
+Expression operator+( const Term& term, double constant )
+{
+ return Expression( term, constant );
+}
+
+
+inline
+Expression operator-( const Term& term, const Expression& expression )
+{
+ return -expression + term;
+}
+
+
+inline
+Expression operator-( const Term& first, const Term& second )
+{
+ return first + -second;
+}
+
+
+inline
+Expression operator-( const Term& term, const Variable& variable )
+{
+ return term + -variable;
+}
+
+
+inline
+Expression operator-( const Term& term, double constant )
+{
+ return term + -constant;
+}
+
+
+// Variable add and subtract
+
+inline
+Expression operator+( const Variable& variable, const Expression& expression )
+{
+ return expression + variable;
+}
+
+
+inline
+Expression operator+( const Variable& variable, const Term& term )
+{
+ return term + variable;
+}
+
+
+inline
+Expression operator+( const Variable& first, const Variable& second )
+{
+ return Term( first ) + second;
+}
+
+
+inline
+Expression operator+( const Variable& variable, double constant )
+{
+ return Term( variable ) + constant;
+}
+
+
+inline
+Expression operator-( const Variable& variable, const Expression& expression )
+{
+ return variable + -expression;
+}
+
+
+inline
+Expression operator-( const Variable& variable, const Term& term )
+{
+ return variable + -term;
+}
+
+
+inline
+Expression operator-( const Variable& first, const Variable& second )
+{
+ return first + -second;
+}
+
+
+inline
+Expression operator-( const Variable& variable, double constant )
+{
+ return variable + -constant;
+}
+
+
+// Double add and subtract
+
+inline
+Expression operator+( double constant, const Expression& expression )
+{
+ return expression + constant;
+}
+
+
+inline
+Expression operator+( double constant, const Term& term )
+{
+ return term + constant;
+}
+
+
+inline
+Expression operator+( double constant, const Variable& variable )
+{
+ return variable + constant;
+}
+
+
+inline
+Expression operator-( double constant, const Expression& expression )
+{
+ return -expression + constant;
+}
+
+
+inline
+Expression operator-( double constant, const Term& term )
+{
+ return -term + constant;
+}
+
+
+inline
+Expression operator-( double constant, const Variable& variable )
+{
+ return -variable + constant;
+}
+
+
+// Expression relations
+
+inline
+Constraint operator==( const Expression& first, const Expression& second )
+{
+ return Constraint( first - second, OP_EQ );
+}
+
+
+inline
+Constraint operator==( const Expression& expression, const Term& term )
+{
+ return expression == Expression( term );
+}
+
+
+inline
+Constraint operator==( const Expression& expression, const Variable& variable )
+{
+ return expression == Term( variable );
+}
+
+
+inline
+Constraint operator==( const Expression& expression, double constant )
+{
+ return expression == Expression( constant );
+}
+
+
+inline
+Constraint operator<=( const Expression& first, const Expression& second )
+{
+ return Constraint( first - second, OP_LE );
+}
+
+
+inline
+Constraint operator<=( const Expression& expression, const Term& term )
+{
+ return expression <= Expression( term );
+}
+
+
+inline
+Constraint operator<=( const Expression& expression, const Variable& variable )
+{
+ return expression <= Term( variable );
+}
+
+
+inline
+Constraint operator<=( const Expression& expression, double constant )
+{
+ return expression <= Expression( constant );
+}
+
+
+inline
+Constraint operator>=( const Expression& first, const Expression& second )
+{
+ return Constraint( first - second, OP_GE );
+}
+
+
+inline
+Constraint operator>=( const Expression& expression, const Term& term )
+{
+ return expression >= Expression( term );
+}
+
+
+inline
+Constraint operator>=( const Expression& expression, const Variable& variable )
+{
+ return expression >= Term( variable );
+}
+
+
+inline
+Constraint operator>=( const Expression& expression, double constant )
+{
+ return expression >= Expression( constant );
+}
+
+
+// Term relations
+
+inline
+Constraint operator==( const Term& term, const Expression& expression )
+{
+ return expression == term;
+}
+
+
+inline
+Constraint operator==( const Term& first, const Term& second )
+{
+ return Expression( first ) == second;
+}
+
+
+inline
+Constraint operator==( const Term& term, const Variable& variable )
+{
+ return Expression( term ) == variable;
+}
+
+
+inline
+Constraint operator==( const Term& term, double constant )
+{
+ return Expression( term ) == constant;
+}
+
+
+inline
+Constraint operator<=( const Term& term, const Expression& expression )
+{
+ return expression >= term;
+}
+
+
+inline
+Constraint operator<=( const Term& first, const Term& second )
+{
+ return Expression( first ) <= second;
+}
+
+
+inline
+Constraint operator<=( const Term& term, const Variable& variable )
+{
+ return Expression( term ) <= variable;
+}
+
+
+inline
+Constraint operator<=( const Term& term, double constant )
+{
+ return Expression( term ) <= constant;
+}
+
+
+inline
+Constraint operator>=( const Term& term, const Expression& expression )
+{
+ return expression <= term;
+}
+
+
+inline
+Constraint operator>=( const Term& first, const Term& second )
+{
+ return Expression( first ) >= second;
+}
+
+
+inline
+Constraint operator>=( const Term& term, const Variable& variable )
+{
+ return Expression( term ) >= variable;
+}
+
+
+inline
+Constraint operator>=( const Term& term, double constant )
+{
+ return Expression( term ) >= constant;
+}
+
+
+// Variable relations
+inline
+Constraint operator==( const Variable& variable, const Expression& expression )
+{
+ return expression == variable;
+}
+
+
+inline
+Constraint operator==( const Variable& variable, const Term& term )
+{
+ return term == variable;
+}
+
+
+inline
+Constraint operator==( const Variable& first, const Variable& second )
+{
+ return Term( first ) == second;
+}
+
+
+inline
+Constraint operator==( const Variable& variable, double constant )
+{
+ return Term( variable ) == constant;
+}
+
+
+inline
+Constraint operator<=( const Variable& variable, const Expression& expression )
+{
+ return expression >= variable;
+}
+
+
+inline
+Constraint operator<=( const Variable& variable, const Term& term )
+{
+ return term >= variable;
+}
+
+
+inline
+Constraint operator<=( const Variable& first, const Variable& second )
+{
+ return Term( first ) <= second;
+}
+
+
+inline
+Constraint operator<=( const Variable& variable, double constant )
+{
+ return Term( variable ) <= constant;
+}
+
+
+inline
+Constraint operator>=( const Variable& variable, const Expression& expression )
+{
+ return expression <= variable;
+}
+
+
+inline
+Constraint operator>=( const Variable& variable, const Term& term )
+{
+ return term <= variable;
+}
+
+
+inline
+Constraint operator>=( const Variable& first, const Variable& second )
+{
+ return Term( first ) >= second;
+}
+
+
+inline
+Constraint operator>=( const Variable& variable, double constant )
+{
+ return Term( variable ) >= constant;
+}
+
+
+// Double relations
+
+inline
+Constraint operator==( double constant, const Expression& expression )
+{
+ return expression == constant;
+}
+
+
+inline
+Constraint operator==( double constant, const Term& term )
+{
+ return term == constant;
+}
+
+
+inline
+Constraint operator==( double constant, const Variable& variable )
+{
+ return variable == constant;
+}
+
+
+inline
+Constraint operator<=( double constant, const Expression& expression )
+{
+ return expression >= constant;
+}
+
+
+inline
+Constraint operator<=( double constant, const Term& term )
+{
+ return term >= constant;
+}
+
+
+inline
+Constraint operator<=( double constant, const Variable& variable )
+{
+ return variable >= constant;
+}
+
+
+inline
+Constraint operator>=( double constant, const Expression& expression )
+{
+ return expression <= constant;
+}
+
+
+inline
+Constraint operator>=( double constant, const Term& term )
+{
+ return term <= constant;
+}
+
+
+inline
+Constraint operator>=( double constant, const Variable& variable )
+{
+ return variable <= constant;
+}
+
+
+// Constraint strength modifier
+
+inline
+Constraint operator|( const Constraint& constraint, double strength )
+{
+ return Constraint( constraint, strength );
+}
+
+
+inline
+Constraint operator|( double strength, const Constraint& constraint )
+{
+ return constraint | strength;
+}
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/term.h b/contrib/python/kiwisolver/py3/kiwi/term.h
new file mode 100644
index 00000000000..1ee962287cc
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/term.h
@@ -0,0 +1,51 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <utility>
+#include "variable.h"
+
+
+namespace kiwi
+{
+
+class Term
+{
+
+public:
+
+ Term( const Variable& variable, double coefficient = 1.0 ) :
+ m_variable( variable ), m_coefficient( coefficient ) {}
+
+ // to facilitate efficient map -> vector copies
+ Term( const std::pair<const Variable, double>& pair ) :
+ m_variable( pair.first ), m_coefficient( pair.second ) {}
+
+ ~Term() {}
+
+ const Variable& variable() const
+ {
+ return m_variable;
+ }
+
+ double coefficient() const
+ {
+ return m_coefficient;
+ }
+
+ double value() const
+ {
+ return m_coefficient * m_variable.value();
+ }
+
+private:
+
+ Variable m_variable;
+ double m_coefficient;
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/util.h b/contrib/python/kiwisolver/py3/kiwi/util.h
new file mode 100644
index 00000000000..0d36a33eb15
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/util.h
@@ -0,0 +1,25 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+
+
+namespace kiwi
+{
+
+namespace impl
+{
+
+inline bool nearZero( double value )
+{
+ const double eps = 1.0e-8;
+ return value < 0.0 ? -value < eps : value < eps;
+}
+
+} // namespace impl
+
+} // namespace
diff --git a/contrib/python/kiwisolver/py3/kiwi/variable.h b/contrib/python/kiwisolver/py3/kiwi/variable.h
new file mode 100644
index 00000000000..eaee93f2a13
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/variable.h
@@ -0,0 +1,121 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <memory>
+#include <string>
+#include "shareddata.h"
+
+
+namespace kiwi
+{
+
+class Variable
+{
+
+public:
+
+ class Context
+ {
+ public:
+ Context() {}
+ virtual ~Context() {} // LCOV_EXCL_LINE
+ };
+
+ Variable( Context* context = 0 ) :
+ m_data( new VariableData( "", context ) ) {}
+
+ Variable( const std::string& name, Context* context = 0 ) :
+ m_data( new VariableData( name, context ) ) {}
+
+ Variable( const char* name, Context* context = 0 ) :
+ m_data( new VariableData( name, context ) ) {}
+
+ ~Variable() {}
+
+ const std::string& name() const
+ {
+ return m_data->m_name;
+ }
+
+ void setName( const char* name )
+ {
+ m_data->m_name = name;
+ }
+
+ void setName( const std::string& name )
+ {
+ m_data->m_name = name;
+ }
+
+ Context* context() const
+ {
+ return m_data->m_context.get();
+ }
+
+ void setContext( Context* context )
+ {
+ m_data->m_context.reset( context );
+ }
+
+ double value() const
+ {
+ return m_data->m_value;
+ }
+
+ void setValue( double value )
+ {
+ m_data->m_value = value;
+ }
+
+ // operator== is used for symbolics
+ bool equals( const Variable& other )
+ {
+ return m_data == other.m_data;
+ }
+
+private:
+
+ class VariableData : public SharedData
+ {
+
+ public:
+
+ VariableData( const std::string& name, Context* context ) :
+ SharedData(),
+ m_name( name ),
+ m_context( context ),
+ m_value( 0.0 ) {}
+
+ VariableData( const char* name, Context* context ) :
+ SharedData(),
+ m_name( name ),
+ m_context( context ),
+ m_value( 0.0 ) {}
+
+ ~VariableData() {}
+
+ std::string m_name;
+ std::auto_ptr<Context> m_context;
+ double m_value;
+
+ private:
+
+ VariableData( const VariableData& other );
+
+ VariableData& operator=( const VariableData& other );
+ };
+
+ SharedDataPtr<VariableData> m_data;
+
+ friend bool operator<( const Variable& lhs, const Variable& rhs )
+ {
+ return lhs.m_data < rhs.m_data;
+ }
+};
+
+} // namespace kiwi
diff --git a/contrib/python/kiwisolver/py3/kiwi/version.h b/contrib/python/kiwisolver/py3/kiwi/version.h
new file mode 100644
index 00000000000..197f3ce1869
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/kiwi/version.h
@@ -0,0 +1,14 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+
+#define KIWI_MAJOR_VERSION 1
+#define KIWI_MINOR_VERSION 0
+#define KIWI_MICRO_VERSION 1
+#define KIWI_VERSION_HEX 0x010001
+#define KIWI_VERSION "1.1.0"
diff --git a/contrib/python/kiwisolver/py3/py/constraint.cpp b/contrib/python/kiwisolver/py3/py/constraint.cpp
new file mode 100644
index 00000000000..2fbdd0aeb83
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/py/constraint.cpp
@@ -0,0 +1,299 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <algorithm>
+#include <sstream>
+#include <Python.h>
+#include <kiwi/kiwi.h>
+#include "pythonhelpers.h"
+#include "types.h"
+#include "util.h"
+
+
+using namespace PythonHelpers;
+
+
+static PyObject*
+Constraint_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
+{
+ static const char *kwlist[] = { "expression", "op", "strength", 0 };
+ PyObject* pyexpr;
+ PyObject* pyop;
+ PyObject* pystrength = 0;
+ if( !PyArg_ParseTupleAndKeywords(
+ args, kwargs, "OO|O:__new__", const_cast<char**>( kwlist ),
+ &pyexpr, &pyop, &pystrength ) )
+ return 0;
+ if( !Expression::TypeCheck( pyexpr ) )
+ return py_expected_type_fail( pyexpr, "Expression" );
+ kiwi::RelationalOperator op;
+ if( !convert_to_relational_op( pyop, op ) )
+ return 0;
+ double strength = kiwi::strength::required;
+ if( pystrength && !convert_to_strength( pystrength, strength ) )
+ return 0;
+ PyObjectPtr pycn( PyType_GenericNew( type, args, kwargs ) );
+ if( !pycn )
+ return 0;
+ Constraint* cn = reinterpret_cast<Constraint*>( pycn.get() );
+ cn->expression = reduce_expression( pyexpr );
+ if( !cn->expression )
+ return 0;
+ kiwi::Expression expr( convert_to_kiwi_expression( cn->expression ) );
+ new( &cn->constraint ) kiwi::Constraint( expr, op, strength );
+ return pycn.release();
+}
+
+
+static void
+Constraint_clear( Constraint* self )
+{
+ Py_CLEAR( self->expression );
+}
+
+
+static int
+Constraint_traverse( Constraint* self, visitproc visit, void* arg )
+{
+ Py_VISIT( self->expression );
+ return 0;
+}
+
+
+static void
+Constraint_dealloc( Constraint* self )
+{
+ PyObject_GC_UnTrack( self );
+ Constraint_clear( self );
+ self->constraint.~Constraint();
+ Py_TYPE( self )->tp_free( pyobject_cast( self ) );
+}
+
+
+static PyObject*
+Constraint_repr( Constraint* self )
+{
+ std::stringstream stream;
+ Expression* expr = reinterpret_cast<Expression*>( self->expression );
+ Py_ssize_t size = PyTuple_GET_SIZE( expr->terms );
+ for( Py_ssize_t i = 0; i < size; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( expr->terms, i );
+ Term* term = reinterpret_cast<Term*>( item );
+ stream << term->coefficient << " * ";
+ stream << reinterpret_cast<Variable*>( term->variable )->variable.name();
+ stream << " + ";
+ }
+ stream << expr->constant;
+ switch( self->constraint.op() )
+ {
+ case kiwi::OP_EQ:
+ stream << " == 0";
+ break;
+ case kiwi::OP_LE:
+ stream << " <= 0";
+ break;
+ case kiwi::OP_GE:
+ stream << " >= 0";
+ break;
+ }
+ stream << " | strength = " << self->constraint.strength();
+ return FROM_STRING( stream.str().c_str() );
+}
+
+
+static PyObject*
+Constraint_expression( Constraint* self )
+{
+ return newref( self->expression );
+}
+
+
+static PyObject*
+Constraint_op( Constraint* self )
+{
+ PyObject* res = 0;
+ switch( self->constraint.op() )
+ {
+ case kiwi::OP_EQ:
+ res = FROM_STRING( "==" );
+ break;
+ case kiwi::OP_LE:
+ res = FROM_STRING( "<=" );
+ break;
+ case kiwi::OP_GE:
+ res = FROM_STRING( ">=" );
+ break;
+ }
+ return res;
+}
+
+
+static PyObject*
+Constraint_strength( Constraint* self )
+{
+ return PyFloat_FromDouble( self->constraint.strength() );
+}
+
+
+static PyObject*
+Constraint_or( PyObject* pyoldcn, PyObject* value )
+{
+ if( !Constraint::TypeCheck( pyoldcn ) )
+ std::swap( pyoldcn, value );
+ double strength;
+ if( !convert_to_strength( value, strength ) )
+ return 0;
+ PyObject* pynewcn = PyType_GenericNew( &Constraint_Type, 0, 0 );
+ if( !pynewcn )
+ return 0;
+ Constraint* oldcn = reinterpret_cast<Constraint*>( pyoldcn );
+ Constraint* newcn = reinterpret_cast<Constraint*>( pynewcn );
+ newcn->expression = newref( oldcn->expression );
+ new( &newcn->constraint ) kiwi::Constraint( oldcn->constraint, strength );
+ return pynewcn;
+}
+
+
+static PyMethodDef
+Constraint_methods[] = {
+ { "expression", ( PyCFunction )Constraint_expression, METH_NOARGS,
+ "Get the expression object for the constraint." },
+ { "op", ( PyCFunction )Constraint_op, METH_NOARGS,
+ "Get the relational operator for the constraint." },
+ { "strength", ( PyCFunction )Constraint_strength, METH_NOARGS,
+ "Get the strength for the constraint." },
+ { 0 } // sentinel
+};
+
+
+static PyNumberMethods
+Constraint_as_number = {
+ 0, /* nb_add */
+ 0, /* nb_subtract */
+ 0, /* nb_multiply */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_divide */
+#endif
+ 0, /* nb_remainder */
+ 0, /* nb_divmod */
+ 0, /* nb_power */
+ 0, /* nb_negative */
+ 0, /* nb_positive */
+ 0, /* nb_absolute */
+#if PY_MAJOR_VERSION >= 3
+ 0, /* nb_bool */
+#else
+ 0, /* nb_nonzero */
+#endif
+ 0, /* nb_invert */
+ 0, /* nb_lshift */
+ 0, /* nb_rshift */
+ 0, /* nb_and */
+ 0, /* nb_xor */
+ (binaryfunc)Constraint_or, /* nb_or */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_coerce */
+#endif
+ 0, /* nb_int */
+ 0, /* nb_long */
+ 0, /* nb_float */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_oct */
+ 0, /* nb_hex */
+#endif
+ 0, /* nb_inplace_add */
+ 0, /* nb_inplace_subtract */
+ 0, /* nb_inplace_multiply */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_inplace_divide */
+#endif
+ 0, /* nb_inplace_remainder */
+ 0, /* nb_inplace_power */
+ 0, /* nb_inplace_lshift */
+ 0, /* nb_inplace_rshift */
+ 0, /* nb_inplace_and */
+ 0, /* nb_inplace_xor */
+ 0, /* nb_inplace_or */
+ (binaryfunc)0, /* nb_floor_divide */
+ (binaryfunc)0, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+#if PY_VERSION_HEX >= 0x02050000
+ (unaryfunc)0, /* nb_index */
+#endif
+#if PY_VERSION_HEX >= 0x03050000
+ (binaryfunc)0, /* nb_matrix_multiply */
+ (binaryfunc)0, /* nb_inplace_matrix_multiply */
+#endif
+};
+
+
+PyTypeObject Constraint_Type = {
+ PyVarObject_HEAD_INIT( &PyType_Type, 0 )
+ "kiwisolver.Constraint", /* tp_name */
+ sizeof( Constraint ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Constraint_dealloc, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03050000
+ ( PyAsyncMethods* )0, /* tp_as_async */
+#elif PY_VERSION_HEX >= 0x03000000
+ ( void* ) 0, /* tp_reserved */
+#else
+ ( cmpfunc )0, /* tp_compare */
+#endif
+ (reprfunc)Constraint_repr, /* tp_repr */
+ (PyNumberMethods*)&Constraint_as_number,/* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+#if PY_MAJOR_VERSION >= 3
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, /* tp_flags */
+#else
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+#endif
+ 0, /* Documentation string */
+ (traverseproc)Constraint_traverse, /* tp_traverse */
+ (inquiry)Constraint_clear, /* tp_clear */
+ (richcmpfunc)0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)Constraint_methods,/* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)Constraint_new, /* tp_new */
+ (freefunc)PyObject_GC_Del, /* tp_free */
+ (inquiry)0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ (destructor)0 /* tp_del */
+};
+
+
+int import_constraint()
+{
+ return PyType_Ready( &Constraint_Type );
+}
diff --git a/contrib/python/kiwisolver/py3/py/expression.cpp b/contrib/python/kiwisolver/py3/py/expression.cpp
new file mode 100644
index 00000000000..5cd34e4c120
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/py/expression.cpp
@@ -0,0 +1,326 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <sstream>
+#include <Python.h>
+#include "pythonhelpers.h"
+#include "symbolics.h"
+#include "types.h"
+#include "util.h"
+
+
+using namespace PythonHelpers;
+
+
+static PyObject*
+Expression_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
+{
+ static const char *kwlist[] = { "terms", "constant", 0 };
+ PyObject* pyterms;
+ PyObject* pyconstant = 0;
+ if( !PyArg_ParseTupleAndKeywords(
+ args, kwargs, "O|O:__new__", const_cast<char**>( kwlist ),
+ &pyterms, &pyconstant ) )
+ return 0;
+ PyObjectPtr terms( PySequence_Tuple( pyterms ) );
+ if( !terms )
+ return 0;
+ Py_ssize_t end = PyTuple_GET_SIZE( terms.get() );
+ for( Py_ssize_t i = 0; i < end; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( terms.get(), i );
+ if( !Term::TypeCheck( item ) )
+ return py_expected_type_fail( item, "Term" );
+ }
+ double constant = 0.0;
+ if( pyconstant && !convert_to_double( pyconstant, constant ) )
+ return 0;
+ PyObject* pyexpr = PyType_GenericNew( type, args, kwargs );
+ if( !pyexpr )
+ return 0;
+ Expression* self = reinterpret_cast<Expression*>( pyexpr );
+ self->terms = terms.release();
+ self->constant = constant;
+ return pyexpr;
+}
+
+
+static void
+Expression_clear( Expression* self )
+{
+ Py_CLEAR( self->terms );
+}
+
+
+static int
+Expression_traverse( Expression* self, visitproc visit, void* arg )
+{
+ Py_VISIT( self->terms );
+ return 0;
+}
+
+
+static void
+Expression_dealloc( Expression* self )
+{
+ PyObject_GC_UnTrack( self );
+ Expression_clear( self );
+ Py_TYPE( self )->tp_free( pyobject_cast( self ) );
+}
+
+
+static PyObject*
+Expression_repr( Expression* self )
+{
+ std::stringstream stream;
+ Py_ssize_t end = PyTuple_GET_SIZE( self->terms );
+ for( Py_ssize_t i = 0; i < end; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( self->terms, i );
+ Term* term = reinterpret_cast<Term*>( item );
+ stream << term->coefficient << " * ";
+ stream << reinterpret_cast<Variable*>( term->variable )->variable.name();
+ stream << " + ";
+ }
+ stream << self->constant;
+ return FROM_STRING( stream.str().c_str() );
+}
+
+
+static PyObject*
+Expression_terms( Expression* self )
+{
+ return newref( self->terms );
+}
+
+
+static PyObject*
+Expression_constant( Expression* self )
+{
+ return PyFloat_FromDouble( self->constant );
+}
+
+
+static PyObject*
+Expression_value( Expression* self )
+{
+ double result = self->constant;
+ Py_ssize_t size = PyTuple_GET_SIZE( self->terms );
+ for( Py_ssize_t i = 0; i < size; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( self->terms, i );
+ Term* term = reinterpret_cast<Term*>( item );
+ Variable* pyvar = reinterpret_cast<Variable*>( term->variable );
+ result += term->coefficient * pyvar->variable.value();
+ }
+ return PyFloat_FromDouble( result );
+}
+
+
+static PyObject*
+Expression_add( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryAdd, Expression>()( first, second );
+}
+
+
+static PyObject*
+Expression_sub( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinarySub, Expression>()( first, second );
+}
+
+
+static PyObject*
+Expression_mul( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryMul, Expression>()( first, second );
+}
+
+
+static PyObject*
+Expression_div( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryDiv, Expression>()( first, second );
+}
+
+
+static PyObject*
+Expression_neg( PyObject* value )
+{
+ return UnaryInvoke<UnaryNeg, Expression>()( value );
+}
+
+
+static PyObject*
+Expression_richcmp( PyObject* first, PyObject* second, int op )
+{
+ switch( op )
+ {
+ case Py_EQ:
+ return BinaryInvoke<CmpEQ, Expression>()( first, second );
+ case Py_LE:
+ return BinaryInvoke<CmpLE, Expression>()( first, second );
+ case Py_GE:
+ return BinaryInvoke<CmpGE, Expression>()( first, second );
+ default:
+ break;
+ }
+ PyErr_Format(
+ PyExc_TypeError,
+ "unsupported operand type(s) for %s: "
+ "'%.100s' and '%.100s'",
+ pyop_str( op ),
+ first->ob_type->tp_name,
+ second->ob_type->tp_name
+ );
+ return 0;
+}
+
+
+static PyMethodDef
+Expression_methods[] = {
+ { "terms", ( PyCFunction )Expression_terms, METH_NOARGS,
+ "Get the tuple of terms for the expression." },
+ { "constant", ( PyCFunction )Expression_constant, METH_NOARGS,
+ "Get the constant for the expression." },
+ { "value", ( PyCFunction )Expression_value, METH_NOARGS,
+ "Get the value for the expression." },
+ { 0 } // sentinel
+};
+
+
+static PyNumberMethods
+Expression_as_number = {
+ (binaryfunc)Expression_add, /* nb_add */
+ (binaryfunc)Expression_sub, /* nb_subtract */
+ (binaryfunc)Expression_mul, /* nb_multiply */
+#if PY_MAJOR_VERSION < 3
+ (binaryfunc)Expression_div, /* nb_divide */
+#endif
+ 0, /* nb_remainder */
+ 0, /* nb_divmod */
+ 0, /* nb_power */
+ (unaryfunc)Expression_neg, /* nb_negative */
+ 0, /* nb_positive */
+ 0, /* nb_absolute */
+#if PY_MAJOR_VERSION >= 3
+ 0, /* nb_bool */
+#else
+ 0, /* nb_nonzero */
+#endif
+ 0, /* nb_invert */
+ 0, /* nb_lshift */
+ 0, /* nb_rshift */
+ 0, /* nb_and */
+ 0, /* nb_xor */
+ (binaryfunc)0, /* nb_or */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_coerce */
+#endif
+ 0, /* nb_int */
+#if PY_MAJOR_VERSION >= 3
+ (void *)0, /* nb_reserved */
+#else
+ 0, /* nb_long */
+#endif
+ 0, /* nb_float */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_oct */
+ 0, /* nb_hex */
+#endif
+ 0, /* nb_inplace_add */
+ 0, /* nb_inplace_subtract */
+ 0, /* nb_inplace_multiply */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_inplace_divide */
+#endif
+ 0, /* nb_inplace_remainder */
+ 0, /* nb_inplace_power */
+ 0, /* nb_inplace_lshift */
+ 0, /* nb_inplace_rshift */
+ 0, /* nb_inplace_and */
+ 0, /* nb_inplace_xor */
+ 0, /* nb_inplace_or */
+ (binaryfunc)0, /* nb_floor_divide */
+ (binaryfunc)Expression_div, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+#if PY_VERSION_HEX >= 0x02050000
+ (unaryfunc)0, /* nb_index */
+#endif
+#if PY_VERSION_HEX >= 0x03050000
+ (binaryfunc)0, /* nb_matrix_multiply */
+ (binaryfunc)0, /* nb_inplace_matrix_multiply */
+#endif
+};
+
+
+PyTypeObject Expression_Type = {
+ PyVarObject_HEAD_INIT( &PyType_Type, 0 )
+ "kiwisolver.Expression", /* tp_name */
+ sizeof( Expression ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Expression_dealloc, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03050000
+ ( PyAsyncMethods* )0, /* tp_as_async */
+#elif PY_VERSION_HEX >= 0x03000000
+ ( void* ) 0, /* tp_reserved */
+#else
+ ( cmpfunc )0, /* tp_compare */
+#endif
+ (reprfunc)Expression_repr, /* tp_repr */
+ (PyNumberMethods*)&Expression_as_number,/* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+#if PY_MAJOR_VERSION >= 3
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE,
+#else
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+#endif
+ 0, /* Documentation string */
+ (traverseproc)Expression_traverse, /* tp_traverse */
+ (inquiry)Expression_clear, /* tp_clear */
+ (richcmpfunc)Expression_richcmp, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)Expression_methods,/* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)Expression_new, /* tp_new */
+ (freefunc)PyObject_GC_Del, /* tp_free */
+ (inquiry)0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ (destructor)0 /* tp_del */
+};
+
+
+int import_expression()
+{
+ return PyType_Ready( &Expression_Type );
+}
diff --git a/contrib/python/kiwisolver/py3/py/kiwisolver.cpp b/contrib/python/kiwisolver/py3/py/kiwisolver.cpp
new file mode 100644
index 00000000000..54b333a2c8b
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/py/kiwisolver.cpp
@@ -0,0 +1,86 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <Python.h>
+#include <kiwi/kiwi.h>
+#include "pythonhelpers.h"
+#include "types.h"
+
+#define PY_KIWI_VERSION "1.1.0"
+
+using namespace PythonHelpers;
+
+static PyMethodDef
+kiwisolver_methods[] = {
+ { 0 } // Sentinel
+};
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef kiwisolver_moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "kiwisolver",
+ NULL,
+ sizeof( struct module_state ),
+ kiwisolver_methods,
+ NULL
+};
+
+PyMODINIT_FUNC
+PyInit_kiwisolver( void )
+#else
+PyMODINIT_FUNC
+initkiwisolver( void )
+#endif
+{
+#if PY_MAJOR_VERSION >= 3
+ PyObject *mod = PyModule_Create( &kiwisolver_moduledef );
+#else
+ PyObject* mod = Py_InitModule( "kiwisolver", kiwisolver_methods );
+#endif
+ if( !mod )
+ INITERROR;
+ if( import_variable() < 0 )
+ INITERROR;
+ if( import_term() < 0 )
+ INITERROR;
+ if( import_expression() < 0 )
+ INITERROR;
+ if( import_constraint() < 0 )
+ INITERROR;
+ if( import_solver() < 0 )
+ INITERROR;
+ if( import_strength() < 0 )
+ INITERROR;
+ PyObject* kiwiversion = FROM_STRING( KIWI_VERSION );
+ if( !kiwiversion )
+ INITERROR;
+ PyObject* pyversion = FROM_STRING( PY_KIWI_VERSION );
+ if( !pyversion )
+ INITERROR;
+ PyObject* pystrength = PyType_GenericNew( &strength_Type, 0, 0 );
+ if( !pystrength )
+ INITERROR;
+
+ PyModule_AddObject( mod, "__version__", pyversion );
+ PyModule_AddObject( mod, "__kiwi_version__", kiwiversion );
+ PyModule_AddObject( mod, "strength", pystrength );
+ PyModule_AddObject( mod, "Variable", newref( pyobject_cast( &Variable_Type ) ) );
+ PyModule_AddObject( mod, "Term", newref( pyobject_cast( &Term_Type ) ) );
+ PyModule_AddObject( mod, "Expression", newref( pyobject_cast( &Expression_Type ) ) );
+ PyModule_AddObject( mod, "Constraint", newref( pyobject_cast( &Constraint_Type ) ) );
+ PyModule_AddObject( mod, "Solver", newref( pyobject_cast( &Solver_Type ) ) );
+ PyModule_AddObject( mod, "DuplicateConstraint", newref( DuplicateConstraint ) );
+ PyModule_AddObject( mod, "UnsatisfiableConstraint", newref( UnsatisfiableConstraint ) );
+ PyModule_AddObject( mod, "UnknownConstraint", newref( UnknownConstraint ) );
+ PyModule_AddObject( mod, "DuplicateEditVariable", newref( DuplicateEditVariable ) );
+ PyModule_AddObject( mod, "UnknownEditVariable", newref( UnknownEditVariable ) );
+ PyModule_AddObject( mod, "BadRequiredStrength", newref( BadRequiredStrength ) );
+
+#if PY_MAJOR_VERSION >= 3
+ return mod;
+#endif
+}
diff --git a/contrib/python/kiwisolver/py3/py/pythonhelpers.h b/contrib/python/kiwisolver/py3/py/pythonhelpers.h
new file mode 100644
index 00000000000..a9e0db634d7
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/py/pythonhelpers.h
@@ -0,0 +1,771 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <Python.h>
+#include <structmember.h>
+#include <string>
+
+#if PY_MAJOR_VERSION >= 3
+#define FROM_STRING PyUnicode_FromString
+#define INITERROR return NULL
+#define MOD_INIT_FUNC(name) PyMODINIT_FUNC PyInit_##name(void)
+#else
+#define FROM_STRING PyString_FromString
+#define INITERROR return
+#define MOD_INIT_FUNC(name) PyMODINIT_FUNC init##name(void)
+#endif
+
+#ifndef Py_RETURN_NOTIMPLEMENTED
+#define Py_RETURN_NOTIMPLEMENTED \
+ return Py_INCREF(Py_NotImplemented), Py_NotImplemented
+#endif
+
+#define pyobject_cast( o ) ( reinterpret_cast<PyObject*>( o ) )
+#define pytype_cast( o ) ( reinterpret_cast<PyTypeObject*>( o ) )
+
+struct module_state {
+ PyObject *error;
+};
+
+
+namespace PythonHelpers
+{
+
+
+/*-----------------------------------------------------------------------------
+| Exception Handling
+|----------------------------------------------------------------------------*/
+inline PyObject*
+py_bad_internal_call( const char* message )
+{
+ PyErr_SetString( PyExc_SystemError, message );
+ return 0;
+}
+
+
+inline PyObject*
+py_type_fail( const char* message )
+{
+ PyErr_SetString( PyExc_TypeError, message );
+ return 0;
+}
+
+
+inline PyObject*
+py_expected_type_fail( PyObject* pyobj, const char* expected_type )
+{
+ PyErr_Format(
+ PyExc_TypeError,
+ "Expected object of type `%s`. Got object of type `%s` instead.",
+ expected_type, pyobj->ob_type->tp_name
+ );
+ return 0;
+}
+
+
+inline PyObject*
+py_value_fail( const char* message )
+{
+ PyErr_SetString( PyExc_ValueError, message );
+ return 0;
+}
+
+
+inline PyObject*
+py_runtime_fail( const char* message )
+{
+ PyErr_SetString( PyExc_RuntimeError, message );
+ return 0;
+}
+
+
+inline PyObject*
+py_attr_fail( const char* message )
+{
+ PyErr_SetString( PyExc_AttributeError, message );
+ return 0;
+}
+
+
+inline PyObject*
+py_no_attr_fail( PyObject* pyobj, const char* attr )
+{
+ PyErr_Format(
+ PyExc_AttributeError,
+ "'%s' object has no attribute '%s'",
+ pyobj->ob_type->tp_name, attr
+ );
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------------
+| Utilities
+|----------------------------------------------------------------------------*/
+inline PyObject*
+newref( PyObject* pyobj )
+{
+ Py_INCREF( pyobj );
+ return pyobj;
+}
+
+
+inline PyObject*
+xnewref( PyObject* pyobj )
+{
+ Py_XINCREF( pyobj );
+ return pyobj;
+}
+
+
+inline PyObject*
+py_bool( bool val )
+{
+ return newref( val ? Py_True : Py_False );
+}
+
+
+inline PyCFunction
+lookup_method( PyTypeObject* type, const char* name )
+{
+ PyMethodDef* method = type->tp_methods;
+ for( ; method->ml_name != 0; ++method )
+ {
+ if( strcmp( method->ml_name, name ) == 0 )
+ return method->ml_meth;
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------------
+| Object Ptr
+|----------------------------------------------------------------------------*/
+class PyObjectPtr {
+
+public:
+
+ PyObjectPtr() : m_pyobj( 0 ) {}
+
+ PyObjectPtr( const PyObjectPtr& objptr ) :
+ m_pyobj( PythonHelpers::xnewref( objptr.m_pyobj ) ) {}
+
+ PyObjectPtr( PyObject* pyobj ) : m_pyobj( pyobj ) {}
+
+ ~PyObjectPtr()
+ {
+ xdecref_release();
+ }
+
+ PyObject* get() const
+ {
+ return m_pyobj;
+ }
+
+ void set( PyObject* pyobj )
+ {
+ PyObject* old = m_pyobj;
+ m_pyobj = pyobj;
+ Py_XDECREF( old );
+ }
+
+ PyObject* release()
+ {
+ PyObject* pyobj = m_pyobj;
+ m_pyobj = 0;
+ return pyobj;
+ }
+
+ PyObject* decref_release()
+ {
+ PyObject* pyobj = m_pyobj;
+ m_pyobj = 0;
+ Py_DECREF( pyobj );
+ return pyobj;
+ }
+
+ PyObject* xdecref_release()
+ {
+ PyObject* pyobj = m_pyobj;
+ m_pyobj = 0;
+ Py_XDECREF( pyobj );
+ return pyobj;
+ }
+
+ PyObject* incref_release()
+ {
+ PyObject* pyobj = m_pyobj;
+ m_pyobj = 0;
+ Py_INCREF( pyobj );
+ return pyobj;
+ }
+
+ PyObject* xincref_release()
+ {
+ PyObject* pyobj = m_pyobj;
+ m_pyobj = 0;
+ Py_XINCREF( pyobj );
+ return pyobj;
+ }
+
+ void incref() const
+ {
+ Py_INCREF( m_pyobj );
+ }
+
+ void decref() const
+ {
+ Py_DECREF( m_pyobj );
+ }
+
+ void xincref() const
+ {
+ Py_XINCREF( m_pyobj );
+ }
+
+ void xdecref() const
+ {
+ Py_XDECREF( m_pyobj );
+ }
+
+ PyObject* newref() const
+ {
+ Py_INCREF( m_pyobj );
+ return m_pyobj;
+ }
+
+ PyObject* xnewref() const
+ {
+ Py_XINCREF( m_pyobj );
+ return m_pyobj;
+ }
+
+ size_t refcount() const
+ {
+ if( m_pyobj )
+ return m_pyobj->ob_refcnt;
+ return 0;
+ }
+
+ bool is_true( bool clear_err=true ) const
+ {
+ int truth = PyObject_IsTrue( m_pyobj );
+ if( truth == 1 )
+ return true;
+ if( truth == 0 )
+ return false;
+ if( clear_err )
+ PyErr_Clear();
+ return false;
+ }
+
+ bool is_None() const
+ {
+ return m_pyobj == Py_None;
+ }
+
+ bool is_True() const
+ {
+ return m_pyobj == Py_True;
+ }
+
+ bool is_False() const
+ {
+ return m_pyobj == Py_False;
+ }
+
+ bool load_dict( PyObjectPtr& out, bool forcecreate=false )
+ {
+ PyObject** dict = _PyObject_GetDictPtr( m_pyobj );
+ if( !dict )
+ return false;
+ if( forcecreate && !*dict )
+ *dict = PyDict_New();
+ out = PythonHelpers::xnewref( *dict );
+ return true;
+ }
+
+ bool richcompare( PyObject* other, int opid, bool clear_err=true )
+ {
+ int r = PyObject_RichCompareBool( m_pyobj, other, opid );
+ if( r == 1 )
+ return true;
+ if( r == 0 )
+ return false;
+ if( clear_err && PyErr_Occurred() )
+ PyErr_Clear();
+ return false;
+ }
+
+ bool richcompare( PyObjectPtr& other, int opid, bool clear_err=true )
+ {
+ return richcompare( other.m_pyobj, opid, clear_err );
+ }
+
+ bool hasattr( PyObject* attr )
+ {
+ return PyObject_HasAttr( m_pyobj, attr ) == 1;
+ }
+
+ bool hasattr( PyObjectPtr& attr )
+ {
+ return PyObject_HasAttr( m_pyobj, attr.get() ) == 1;
+ }
+
+ bool hasattr( const char* attr )
+ {
+ return PyObject_HasAttrString( m_pyobj, attr ) == 1;
+ }
+
+ bool hasattr( std::string& attr )
+ {
+ return hasattr( attr.c_str() );
+ }
+
+ PyObjectPtr getattr( PyObject* attr )
+ {
+ return PyObjectPtr( PyObject_GetAttr( m_pyobj, attr ) );
+ }
+
+ PyObjectPtr getattr( PyObjectPtr& attr )
+ {
+ return PyObjectPtr( PyObject_GetAttr( m_pyobj, attr.get() ) );
+ }
+
+ PyObjectPtr getattr( const char* attr )
+ {
+ return PyObjectPtr( PyObject_GetAttrString( m_pyobj, attr ) );
+ }
+
+ PyObjectPtr getattr( std::string& attr )
+ {
+ return getattr( attr.c_str() );
+ }
+
+ bool setattr( PyObject* attr, PyObject* value )
+ {
+ return PyObject_SetAttr( m_pyobj, attr, value ) == 0;
+ }
+
+ bool setattr( PyObjectPtr& attr, PyObjectPtr& value )
+ {
+ return PyObject_SetAttr( m_pyobj, attr.get(), value.get() ) == 0;
+ }
+
+ PyObjectPtr operator()( PyObjectPtr& args ) const
+ {
+ return PyObjectPtr( PyObject_Call( m_pyobj, args.get(), 0 ) );
+ }
+
+ PyObjectPtr operator()( PyObjectPtr& args, PyObjectPtr& kwargs ) const
+ {
+ return PyObjectPtr( PyObject_Call( m_pyobj, args.get(), kwargs.get() ) );
+ }
+
+ operator void*() const
+ {
+ return static_cast<void*>( m_pyobj );
+ }
+
+ PyObjectPtr& operator=( const PyObjectPtr& rhs )
+ {
+ PyObject* old = m_pyobj;
+ m_pyobj = rhs.m_pyobj;
+ Py_XINCREF( m_pyobj );
+ Py_XDECREF( old );
+ return *this;
+ }
+
+ PyObjectPtr& operator=( PyObject* rhs )
+ {
+ PyObject* old = m_pyobj;
+ m_pyobj = rhs;
+ Py_XDECREF( old );
+ return *this;
+ }
+
+protected:
+
+ PyObject* m_pyobj;
+
+};
+
+
+inline bool
+operator!=( const PyObjectPtr& lhs, const PyObjectPtr& rhs )
+{
+ return lhs.get() != rhs.get();
+}
+
+
+inline bool
+operator!=( const PyObject* lhs, const PyObjectPtr& rhs )
+{
+ return lhs != rhs.get();
+}
+
+
+inline bool
+operator!=( const PyObjectPtr& lhs, const PyObject* rhs )
+{
+ return lhs.get() != rhs;
+}
+
+
+inline bool
+operator==( const PyObjectPtr& lhs, const PyObjectPtr& rhs )
+{
+ return lhs.get() == rhs.get();
+}
+
+
+inline bool
+operator==( const PyObject* lhs, const PyObjectPtr& rhs )
+{
+ return lhs == rhs.get();
+}
+
+
+inline bool
+operator==( const PyObjectPtr& lhs, const PyObject* rhs )
+{
+ return lhs.get() == rhs;
+}
+
+
+/*-----------------------------------------------------------------------------
+| Tuple Ptr
+|----------------------------------------------------------------------------*/
+class PyTuplePtr : public PyObjectPtr {
+
+public:
+
+ PyTuplePtr() : PyObjectPtr() {}
+
+ PyTuplePtr( const PyObjectPtr& objptr ) : PyObjectPtr( objptr ) {}
+
+ PyTuplePtr( PyObject* pytuple ) : PyObjectPtr( pytuple ) {}
+
+ bool check()
+ {
+ return PyTuple_Check( m_pyobj );
+ }
+
+ bool check_exact()
+ {
+ return PyTuple_CheckExact( m_pyobj );
+ }
+
+ Py_ssize_t size() const
+ {
+ return PyTuple_GET_SIZE( m_pyobj );
+ }
+
+ PyObjectPtr get_item( Py_ssize_t index ) const
+ {
+ return PyObjectPtr( PythonHelpers::newref( PyTuple_GET_ITEM( m_pyobj, index ) ) );
+ }
+
+ void set_item( Py_ssize_t index, PyObject* pyobj )
+ {
+ PyObject* old_item = PyTuple_GET_ITEM( m_pyobj, index );
+ PyTuple_SET_ITEM( m_pyobj, index, pyobj );
+ Py_XDECREF( old_item );
+ }
+
+ void set_item( Py_ssize_t index, PyObjectPtr& item )
+ {
+ PyObject* old_item = PyTuple_GET_ITEM( m_pyobj, index );
+ PyTuple_SET_ITEM( m_pyobj, index, item.get() );
+ Py_XINCREF( item.get() );
+ Py_XDECREF( old_item );
+ }
+
+ // pyobj must not be null, only use to fill a new empty tuple
+ void initialize( Py_ssize_t index, PyObject* pyobj )
+ {
+ PyTuple_SET_ITEM( m_pyobj, index, pyobj );
+ }
+
+ // ptr must not be empty, only use to fill a new empty tuple
+ void initialize( Py_ssize_t index, PyObjectPtr& item )
+ {
+ PyTuple_SET_ITEM( m_pyobj, index, item.get() );
+ Py_INCREF( item.get() );
+ }
+
+};
+
+
+/*-----------------------------------------------------------------------------
+| List Ptr
+|----------------------------------------------------------------------------*/
+class PyListPtr : public PyObjectPtr {
+
+public:
+
+ PyListPtr() : PyObjectPtr() {}
+
+ PyListPtr( const PyObjectPtr& objptr ) : PyObjectPtr( objptr ) {}
+
+ PyListPtr( PyObject* pylist ) : PyObjectPtr( pylist ) {}
+
+ bool check() const
+ {
+ return PyList_Check( m_pyobj );
+ }
+
+ bool check_exact() const
+ {
+ return PyList_CheckExact( m_pyobj );
+ }
+
+ Py_ssize_t size() const
+ {
+ return PyList_GET_SIZE( m_pyobj );
+ }
+
+ PyObject* borrow_item( Py_ssize_t index ) const
+ {
+ return PyList_GET_ITEM( m_pyobj, index );
+ }
+
+ PyObjectPtr get_item( Py_ssize_t index ) const
+ {
+ return PyObjectPtr( PythonHelpers::newref( PyList_GET_ITEM( m_pyobj, index ) ) );
+ }
+
+ void set_item( Py_ssize_t index, PyObject* pyobj ) const
+ {
+ PyObject* old_item = PyList_GET_ITEM( m_pyobj, index );
+ PyList_SET_ITEM( m_pyobj, index, pyobj );
+ Py_XDECREF( old_item );
+ }
+
+ void set_item( Py_ssize_t index, PyObjectPtr& item ) const
+ {
+ PyObject* old_item = PyList_GET_ITEM( m_pyobj, index );
+ PyList_SET_ITEM( m_pyobj, index, item.get() );
+ Py_XINCREF( item.get() );
+ Py_XDECREF( old_item );
+ }
+
+ bool del_item( Py_ssize_t index ) const
+ {
+ if( PySequence_DelItem( m_pyobj, index ) == -1 )
+ return false;
+ return true;
+ }
+
+ bool append( PyObjectPtr& pyobj ) const
+ {
+ if( PyList_Append( m_pyobj, pyobj.get() ) == 0 )
+ return true;
+ return false;
+ }
+
+ Py_ssize_t index( PyObjectPtr& item ) const
+ {
+ Py_ssize_t maxidx = size();
+ for( Py_ssize_t idx = 0; idx < maxidx; idx++ )
+ {
+ PyObjectPtr other( get_item( idx ) );
+ if( item.richcompare( other, Py_EQ ) )
+ return idx;
+ }
+ return -1;
+ }
+
+};
+
+
+/*-----------------------------------------------------------------------------
+| Dict Ptr
+|----------------------------------------------------------------------------*/
+class PyDictPtr : public PyObjectPtr {
+
+public:
+
+ PyDictPtr() : PyObjectPtr() {}
+
+ PyDictPtr( const PyObjectPtr& objptr ) : PyObjectPtr( objptr ) {}
+
+ PyDictPtr( PyObject* pydict ) : PyObjectPtr( pydict ) {}
+
+ bool check()
+ {
+ return PyDict_Check( m_pyobj );
+ }
+
+ bool check_exact()
+ {
+ return PyDict_CheckExact( m_pyobj );
+ }
+
+ Py_ssize_t size() const
+ {
+ return PyDict_Size( m_pyobj );
+ }
+
+ PyObjectPtr get_item( PyObject* key ) const
+ {
+ return PyObjectPtr( PythonHelpers::xnewref( PyDict_GetItem( m_pyobj, key ) ) ) ;
+ }
+
+ PyObjectPtr get_item( PyObjectPtr& key ) const
+ {
+ return PyObjectPtr( PythonHelpers::xnewref( PyDict_GetItem( m_pyobj, key.get() ) ) );
+ }
+
+ PyObjectPtr get_item( const char* key ) const
+ {
+ return PyObjectPtr( PythonHelpers::xnewref( PyDict_GetItemString( m_pyobj, key ) ) );
+ }
+
+ PyObjectPtr get_item( std::string& key ) const
+ {
+ return get_item( key.c_str() );
+ }
+
+ bool set_item( PyObject* key, PyObject* value ) const
+ {
+ if( PyDict_SetItem( m_pyobj, key, value ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool set_item( PyObject* key, PyObjectPtr& value ) const
+ {
+ if( PyDict_SetItem( m_pyobj, key, value.get() ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool set_item( PyObjectPtr& key, PyObject* value ) const
+ {
+ if( PyDict_SetItem( m_pyobj, key.get(), value ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool set_item( PyObjectPtr& key, PyObjectPtr& value ) const
+ {
+ if( PyDict_SetItem( m_pyobj, key.get(), value.get() ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool set_item( const char* key, PyObjectPtr& value ) const
+ {
+ if( PyDict_SetItemString( m_pyobj, key, value.get() ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool set_item( const char* key, PyObject* value ) const
+ {
+ if( PyDict_SetItemString( m_pyobj, key, value ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool set_item( std::string& key, PyObjectPtr& value ) const
+ {
+ return set_item( key.c_str(), value );
+ }
+
+ bool del_item( PyObjectPtr& key ) const
+ {
+ if( PyDict_DelItem( m_pyobj, key.get() ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool del_item( const char* key ) const
+ {
+ if( PyDict_DelItemString( m_pyobj, key ) == 0 )
+ return true;
+ return false;
+ }
+
+ bool del_item( std::string& key ) const
+ {
+ return del_item( key.c_str() );
+ }
+
+};
+
+
+/*-----------------------------------------------------------------------------
+| Method Ptr
+|----------------------------------------------------------------------------*/
+class PyMethodPtr : public PyObjectPtr {
+
+public:
+
+ PyMethodPtr() : PyObjectPtr() {}
+
+ PyMethodPtr( const PyObjectPtr& objptr ) : PyObjectPtr( objptr ) {}
+
+ PyMethodPtr( PyObject* pymethod ) : PyObjectPtr( pymethod ) {}
+
+ bool check()
+ {
+ return PyMethod_Check( m_pyobj );
+ }
+
+ PyObjectPtr get_self() const
+ {
+ return PyObjectPtr( PythonHelpers::xnewref( PyMethod_GET_SELF( m_pyobj ) ) );
+ }
+
+ PyObjectPtr get_function() const
+ {
+ return PyObjectPtr( PythonHelpers::xnewref( PyMethod_GET_FUNCTION( m_pyobj ) ) );
+ }
+
+#if PY_MAJOR_VERSION < 3
+ PyObjectPtr get_class() const
+ {
+ return PyObjectPtr( PythonHelpers::xnewref( PyMethod_GET_CLASS( m_pyobj ) ) );
+ }
+#endif
+};
+
+
+/*-----------------------------------------------------------------------------
+| Weakref Ptr
+|----------------------------------------------------------------------------*/
+class PyWeakrefPtr : public PyObjectPtr {
+
+public:
+
+ PyWeakrefPtr() : PyObjectPtr() {}
+
+ PyWeakrefPtr( const PyObjectPtr& objptr ) : PyObjectPtr( objptr ) {}
+
+ PyWeakrefPtr( PyObject* pyweakref ) : PyObjectPtr( pyweakref ) {}
+
+ bool check()
+ {
+ return PyWeakref_CheckRef( m_pyobj );
+ }
+
+ bool check_exact()
+ {
+ return PyWeakref_CheckRefExact( m_pyobj );
+ }
+
+ PyObjectPtr get_object() const
+ {
+ return PyObjectPtr( PythonHelpers::newref( PyWeakref_GET_OBJECT( m_pyobj ) ) );
+ }
+
+};
+
+} // namespace PythonHelpers
diff --git a/contrib/python/kiwisolver/py3/py/solver.cpp b/contrib/python/kiwisolver/py3/py/solver.cpp
new file mode 100644
index 00000000000..7a2ef23ca33
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/py/solver.cpp
@@ -0,0 +1,333 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <Python.h>
+#include <kiwi/kiwi.h>
+#include "pythonhelpers.h"
+#include "types.h"
+#include "util.h"
+
+
+using namespace PythonHelpers;
+
+
+static PyObject*
+Solver_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
+{
+ if( PyTuple_GET_SIZE( args ) != 0 || ( kwargs && PyDict_Size( kwargs ) != 0 ) )
+ return py_type_fail( "Solver.__new__ takes no arguments" );
+ PyObject* pysolver = PyType_GenericNew( type, args, kwargs );
+ if( !pysolver )
+ return 0;
+ Solver* self = reinterpret_cast<Solver*>( pysolver );
+ new( &self->solver ) kiwi::Solver();
+ return pysolver;
+}
+
+
+static void
+Solver_dealloc( Solver* self )
+{
+ self->solver.~Solver();
+ Py_TYPE( self )->tp_free( pyobject_cast( self ) );
+}
+
+
+static PyObject*
+Solver_addConstraint( Solver* self, PyObject* other )
+{
+ if( !Constraint::TypeCheck( other ) )
+ return py_expected_type_fail( other, "Constraint" );
+ Constraint* cn = reinterpret_cast<Constraint*>( other );
+ try
+ {
+ self->solver.addConstraint( cn->constraint );
+ }
+ catch( const kiwi::DuplicateConstraint& )
+ {
+ PyErr_SetObject( DuplicateConstraint, other );
+ return 0;
+ }
+ catch( const kiwi::UnsatisfiableConstraint& )
+ {
+ PyErr_SetObject( UnsatisfiableConstraint, other );
+ return 0;
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_removeConstraint( Solver* self, PyObject* other )
+{
+ if( !Constraint::TypeCheck( other ) )
+ return py_expected_type_fail( other, "Constraint" );
+ Constraint* cn = reinterpret_cast<Constraint*>( other );
+ try
+ {
+ self->solver.removeConstraint( cn->constraint );
+ }
+ catch( const kiwi::UnknownConstraint& )
+ {
+ PyErr_SetObject( UnknownConstraint, other );
+ return 0;
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_hasConstraint( Solver* self, PyObject* other )
+{
+ if( !Constraint::TypeCheck( other ) )
+ return py_expected_type_fail( other, "Constraint" );
+ Constraint* cn = reinterpret_cast<Constraint*>( other );
+ return newref( self->solver.hasConstraint( cn->constraint ) ? Py_True : Py_False );
+}
+
+
+static PyObject*
+Solver_addEditVariable( Solver* self, PyObject* args )
+{
+ PyObject* pyvar;
+ PyObject* pystrength;
+ if( !PyArg_ParseTuple( args, "OO", &pyvar, &pystrength ) )
+ return 0;
+ if( !Variable::TypeCheck( pyvar ) )
+ return py_expected_type_fail( pyvar, "Variable" );
+ double strength;
+ if( !convert_to_strength( pystrength, strength ) )
+ return 0;
+ Variable* var = reinterpret_cast<Variable*>( pyvar );
+ try
+ {
+ self->solver.addEditVariable( var->variable, strength );
+ }
+ catch( const kiwi::DuplicateEditVariable& )
+ {
+ PyErr_SetObject( DuplicateEditVariable, pyvar );
+ return 0;
+ }
+ catch( const kiwi::BadRequiredStrength& e )
+ {
+ PyErr_SetString( BadRequiredStrength, e.what() );
+ return 0;
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_removeEditVariable( Solver* self, PyObject* other )
+{
+ if( !Variable::TypeCheck( other ) )
+ return py_expected_type_fail( other, "Variable" );
+ Variable* var = reinterpret_cast<Variable*>( other );
+ try
+ {
+ self->solver.removeEditVariable( var->variable );
+ }
+ catch( const kiwi::UnknownEditVariable& )
+ {
+ PyErr_SetObject( UnknownEditVariable, other );
+ return 0;
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_hasEditVariable( Solver* self, PyObject* other )
+{
+ if( !Variable::TypeCheck( other ) )
+ return py_expected_type_fail( other, "Variable" );
+ Variable* var = reinterpret_cast<Variable*>( other );
+ return newref( self->solver.hasEditVariable( var->variable ) ? Py_True : Py_False );
+}
+
+
+static PyObject*
+Solver_suggestValue( Solver* self, PyObject* args )
+{
+ PyObject* pyvar;
+ PyObject* pyvalue;
+ if( !PyArg_ParseTuple( args, "OO", &pyvar, &pyvalue ) )
+ return 0;
+ if( !Variable::TypeCheck( pyvar ) )
+ return py_expected_type_fail( pyvar, "Variable" );
+ double value;
+ if( !convert_to_double( pyvalue, value ) )
+ return 0;
+ Variable* var = reinterpret_cast<Variable*>( pyvar );
+ try
+ {
+ self->solver.suggestValue( var->variable, value );
+ }
+ catch( const kiwi::UnknownEditVariable& )
+ {
+ PyErr_SetObject( UnknownEditVariable, pyvar );
+ return 0;
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_updateVariables( Solver* self )
+{
+ self->solver.updateVariables();
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_reset( Solver* self )
+{
+ self->solver.reset();
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Solver_dump( Solver* self )
+{
+ PyObjectPtr dump_str( PyUnicode_FromString( self->solver.dumps().c_str() ) );
+ PyObject_Print( dump_str.get(), stdout, 0 );
+ Py_RETURN_NONE;
+}
+
+static PyObject*
+Solver_dumps( Solver* self )
+{
+ return PyUnicode_FromString( self->solver.dumps().c_str() );
+}
+
+static PyMethodDef
+Solver_methods[] = {
+ { "addConstraint", ( PyCFunction )Solver_addConstraint, METH_O,
+ "Add a constraint to the solver." },
+ { "removeConstraint", ( PyCFunction )Solver_removeConstraint, METH_O,
+ "Remove a constraint from the solver." },
+ { "hasConstraint", ( PyCFunction )Solver_hasConstraint, METH_O,
+ "Check whether the solver contains a constraint." },
+ { "addEditVariable", ( PyCFunction )Solver_addEditVariable, METH_VARARGS,
+ "Add an edit variable to the solver." },
+ { "removeEditVariable", ( PyCFunction )Solver_removeEditVariable, METH_O,
+ "Remove an edit variable from the solver." },
+ { "hasEditVariable", ( PyCFunction )Solver_hasEditVariable, METH_O,
+ "Check whether the solver contains an edit variable." },
+ { "suggestValue", ( PyCFunction )Solver_suggestValue, METH_VARARGS,
+ "Suggest a desired value for an edit variable." },
+ { "updateVariables", ( PyCFunction )Solver_updateVariables, METH_NOARGS,
+ "Update the values of the solver variables." },
+ { "reset", ( PyCFunction )Solver_reset, METH_NOARGS,
+ "Reset the solver to the initial empty starting condition." },
+ { "dump", ( PyCFunction )Solver_dump, METH_NOARGS,
+ "Dump a representation of the solver internals to stdout." },
+ { "dumps", ( PyCFunction )Solver_dumps, METH_NOARGS,
+ "Dump a representation of the solver internals to a string." },
+ { 0 } // sentinel
+};
+
+
+PyTypeObject Solver_Type = {
+ PyVarObject_HEAD_INIT( &PyType_Type, 0 )
+ "kiwisolver.Solver", /* tp_name */
+ sizeof( Solver ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Solver_dealloc, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03050000
+ ( PyAsyncMethods* )0, /* tp_as_async */
+#elif PY_VERSION_HEX >= 0x03000000
+ ( void* ) 0, /* tp_reserved */
+#else
+ ( cmpfunc )0, /* tp_compare */
+#endif
+ (reprfunc)0, /* tp_repr */
+ (PyNumberMethods*)0, /* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
+ 0, /* Documentation string */
+ (traverseproc)0, /* tp_traverse */
+ (inquiry)0, /* tp_clear */
+ (richcmpfunc)0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)Solver_methods, /* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)Solver_new, /* tp_new */
+ (freefunc)PyObject_Del, /* tp_free */
+ (inquiry)0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ (destructor)0 /* tp_del */
+};
+
+
+PyObject* DuplicateConstraint;
+
+PyObject* UnsatisfiableConstraint;
+
+PyObject* UnknownConstraint;
+
+PyObject* DuplicateEditVariable;
+
+PyObject* UnknownEditVariable;
+
+PyObject* BadRequiredStrength;
+
+
+int import_solver()
+{
+ DuplicateConstraint = PyErr_NewException(
+ const_cast<char*>( "kiwisolver.DuplicateConstraint" ), 0, 0 );
+ if( !DuplicateConstraint )
+ return -1;
+ UnsatisfiableConstraint = PyErr_NewException(
+ const_cast<char*>( "kiwisolver.UnsatisfiableConstraint" ), 0, 0 );
+ if( !UnsatisfiableConstraint )
+ return -1;
+ UnknownConstraint = PyErr_NewException(
+ const_cast<char*>( "kiwisolver.UnknownConstraint" ), 0, 0 );
+ if( !UnknownConstraint )
+ return -1;
+ DuplicateEditVariable = PyErr_NewException(
+ const_cast<char*>( "kiwisolver.DuplicateEditVariable" ), 0, 0 );
+ if( !DuplicateEditVariable )
+ return -1;
+ UnknownEditVariable = PyErr_NewException(
+ const_cast<char*>( "kiwisolver.UnknownEditVariable" ), 0, 0 );
+ if( !UnknownEditVariable )
+ return -1;
+ BadRequiredStrength = PyErr_NewException(
+ const_cast<char*>( "kiwisolver.BadRequiredStrength" ), 0, 0 );
+ if( !BadRequiredStrength )
+ return -1;
+ return PyType_Ready( &Solver_Type );
+}
diff --git a/contrib/python/kiwisolver/py3/py/strength.cpp b/contrib/python/kiwisolver/py3/py/strength.cpp
new file mode 100644
index 00000000000..df1552d1947
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/py/strength.cpp
@@ -0,0 +1,162 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <Python.h>
+#include <kiwi/kiwi.h>
+#include "pythonhelpers.h"
+#include "util.h"
+
+
+using namespace PythonHelpers;
+
+
+struct strength
+{
+ PyObject_HEAD;
+};
+
+
+static void
+strength_dealloc( PyObject* self )
+{
+ Py_TYPE( self )->tp_free( self );
+}
+
+
+static PyObject*
+strength_weak( strength* self )
+{
+ return PyFloat_FromDouble( kiwi::strength::weak );
+}
+
+
+static PyObject*
+strength_medium( strength* self )
+{
+ return PyFloat_FromDouble( kiwi::strength::medium );
+}
+
+
+static PyObject*
+strength_strong( strength* self )
+{
+ return PyFloat_FromDouble( kiwi::strength::strong );
+}
+
+
+static PyObject*
+strength_required( strength* self )
+{
+ return PyFloat_FromDouble( kiwi::strength::required );
+}
+
+
+static PyObject*
+strength_create( strength* self, PyObject* args )
+{
+ PyObject* pya;
+ PyObject* pyb;
+ PyObject* pyc;
+ PyObject* pyw = 0;
+ if( !PyArg_ParseTuple( args, "OOO|O", &pya, &pyb, &pyc, &pyw ) )
+ return 0;
+ double a, b, c;
+ double w = 1.0;
+ if( !convert_to_double( pya, a ) )
+ return 0;
+ if( !convert_to_double( pyb, b ) )
+ return 0;
+ if( !convert_to_double( pyc, c ) )
+ return 0;
+ if( pyw && !convert_to_double( pyw, w ) )
+ return 0;
+ return PyFloat_FromDouble( kiwi::strength::create( a, b, c, w ) );
+}
+
+
+static PyGetSetDef
+strength_getset[] = {
+ { "weak", ( getter )strength_weak, 0,
+ "The predefined weak strength." },
+ { "medium", ( getter )strength_medium, 0,
+ "The predefined medium strength." },
+ { "strong", ( getter )strength_strong, 0,
+ "The predefined strong strength." },
+ { "required", ( getter )strength_required, 0,
+ "The predefined required strength." },
+ { 0 } // sentinel
+};
+
+
+static PyMethodDef
+strength_methods[] = {
+ { "create", ( PyCFunction )strength_create, METH_VARARGS,
+ "Create a strength from constituent values and optional weight." },
+ { 0 } // sentinel
+};
+
+
+PyTypeObject strength_Type = {
+ PyVarObject_HEAD_INIT( &PyType_Type, 0 )
+ "kiwisolver.strength", /* tp_name */
+ sizeof( strength ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)strength_dealloc, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03050000
+ ( PyAsyncMethods* )0, /* tp_as_async */
+#elif PY_VERSION_HEX >= 0x03000000
+ ( void* ) 0, /* tp_reserved */
+#else
+ ( cmpfunc )0, /* tp_compare */
+#endif
+ (reprfunc)0, /* tp_repr */
+ (PyNumberMethods*)0, /* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ 0, /* Documentation string */
+ (traverseproc)0, /* tp_traverse */
+ (inquiry)0, /* tp_clear */
+ (richcmpfunc)0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)strength_methods, /* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ strength_getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)0, /* tp_new */
+ (freefunc)PyObject_Del, /* tp_free */
+ (inquiry)0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ (destructor)0 /* tp_del */
+};
+
+
+int import_strength()
+{
+ return PyType_Ready( &strength_Type );
+}
diff --git a/contrib/python/kiwisolver/py3/py/symbolics.h b/contrib/python/kiwisolver/py3/py/symbolics.h
new file mode 100644
index 00000000000..ac575537403
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/py/symbolics.h
@@ -0,0 +1,620 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <Python.h>
+#include "pythonhelpers.h"
+#include "types.h"
+#include "util.h"
+
+
+template<typename Op, typename T>
+struct UnaryInvoke
+{
+ PyObject* operator()( PyObject* value )
+ {
+ return Op()( reinterpret_cast<T*>( value ) );
+ }
+};
+
+
+template<typename Op, typename T>
+struct BinaryInvoke
+{
+ PyObject* operator()( PyObject* first, PyObject* second )
+ {
+ if( T::TypeCheck( first ) )
+ return invoke<Normal>( reinterpret_cast<T*>( first ), second );
+ return invoke<Reverse>( reinterpret_cast<T*>( second ), first );
+ }
+
+ struct Normal
+ {
+ template<typename U>
+ PyObject* operator()( T* primary, U secondary )
+ {
+ return Op()( primary, secondary );
+ }
+ };
+
+ struct Reverse
+ {
+ template<typename U>
+ PyObject* operator()( T* primary, U secondary )
+ {
+ return Op()( secondary, primary );
+ }
+ };
+
+ template<typename Invk>
+ PyObject* invoke( T* primary, PyObject* secondary )
+ {
+ if( Expression::TypeCheck( secondary ) )
+ return Invk()( primary, reinterpret_cast<Expression*>( secondary ) );
+ if( Term::TypeCheck( secondary ) )
+ return Invk()( primary, reinterpret_cast<Term*>( secondary ) );
+ if( Variable::TypeCheck( secondary ) )
+ return Invk()( primary, reinterpret_cast<Variable*>( secondary ) );
+ if( PyFloat_Check( secondary ) )
+ return Invk()( primary, PyFloat_AS_DOUBLE( secondary ) );
+#if PY_MAJOR_VERSION < 3
+ if( PyInt_Check( secondary ) )
+ return Invk()( primary, double( PyInt_AS_LONG( secondary ) ) );
+#endif
+ if( PyLong_Check( secondary ) )
+ {
+ double v = PyLong_AsDouble( secondary );
+ if( v == -1 && PyErr_Occurred() )
+ return 0;
+ return Invk()( primary, v );
+ }
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+};
+
+
+struct BinaryMul
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+};
+
+
+template<> inline
+PyObject* BinaryMul::operator()( Variable* first, double second )
+{
+ PyObject* pyterm = PyType_GenericNew( &Term_Type, 0, 0 );
+ if( !pyterm )
+ return 0;
+ Term* term = reinterpret_cast<Term*>( pyterm );
+ term->variable = PythonHelpers::newref( pyobject_cast( first ) );
+ term->coefficient = second;
+ return pyterm;
+}
+
+
+template<> inline
+PyObject* BinaryMul::operator()( Term* first, double second )
+{
+ PyObject* pyterm = PyType_GenericNew( &Term_Type, 0, 0 );
+ if( !pyterm )
+ return 0;
+ Term* term = reinterpret_cast<Term*>( pyterm );
+ term->variable = PythonHelpers::newref( first->variable );
+ term->coefficient = first->coefficient * second;
+ return pyterm;
+}
+
+
+template<> inline
+PyObject* BinaryMul::operator()( Expression* first, double second )
+{
+ using namespace PythonHelpers;
+ PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
+ if( !pyexpr )
+ return 0;
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
+ PyObjectPtr terms( PyTuple_New( PyTuple_GET_SIZE( first->terms ) ) );
+ if( !terms )
+ return 0;
+ Py_ssize_t end = PyTuple_GET_SIZE( first->terms );
+ for( Py_ssize_t i = 0; i < end; ++i ) // memset 0 for safe error return
+ PyTuple_SET_ITEM( terms.get(), i, 0 );
+ for( Py_ssize_t i = 0; i < end; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( first->terms, i );
+ PyObject* term = BinaryMul()( reinterpret_cast<Term*>( item ), second );
+ if( !term )
+ return 0;
+ PyTuple_SET_ITEM( terms.get(), i, term );
+ }
+ expr->terms = terms.release();
+ expr->constant = first->constant * second;
+ return pyexpr.release();
+}
+
+
+template<> inline
+PyObject* BinaryMul::operator()( double first, Variable* second )
+{
+ return operator()( second, first );
+}
+
+
+template<> inline
+PyObject* BinaryMul::operator()( double first, Term* second )
+{
+ return operator()( second, first );
+}
+
+
+template<> inline
+PyObject* BinaryMul::operator()( double first, Expression* second )
+{
+ return operator()( second, first );
+}
+
+
+struct BinaryDiv
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+};
+
+
+template<> inline
+PyObject* BinaryDiv::operator()( Variable* first, double second )
+{
+ if( second == 0.0 )
+ {
+ PyErr_SetString( PyExc_ZeroDivisionError, "float division by zero" );
+ return 0;
+ }
+ return BinaryMul()( first, 1.0 / second );
+}
+
+
+template<> inline
+PyObject* BinaryDiv::operator()( Term* first, double second )
+{
+ if( second == 0.0 )
+ {
+ PyErr_SetString( PyExc_ZeroDivisionError, "float division by zero" );
+ return 0;
+ }
+ return BinaryMul()( first, 1.0 / second );
+}
+
+
+template<> inline
+PyObject* BinaryDiv::operator()( Expression* first, double second )
+{
+ if( second == 0.0 )
+ {
+ PyErr_SetString( PyExc_ZeroDivisionError, "float division by zero" );
+ return 0;
+ }
+ return BinaryMul()( first, 1.0 / second );
+}
+
+
+struct UnaryNeg
+{
+ template<typename T>
+ PyObject* operator()( T value )
+ {
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+};
+
+
+template<> inline
+PyObject* UnaryNeg::operator()( Variable* value )
+{
+ return BinaryMul()( value, -1.0 );
+}
+
+
+template<> inline
+PyObject* UnaryNeg::operator()( Term* value )
+{
+ return BinaryMul()( value, -1.0 );
+}
+
+
+template<> inline
+PyObject* UnaryNeg::operator()( Expression* value )
+{
+ return BinaryMul()( value, -1.0 );
+}
+
+
+struct BinaryAdd
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+};
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Expression* first, Expression* second )
+{
+ PythonHelpers::PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
+ if( !pyexpr )
+ return 0;
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
+ expr->constant = first->constant + second->constant;
+ expr->terms = PySequence_Concat( first->terms, second->terms );
+ if( !expr->terms )
+ return 0;
+ return pyexpr.release();
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Expression* first, Term* second )
+{
+ using namespace PythonHelpers;
+ PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
+ if( !pyexpr )
+ return 0;
+ PyObject* terms = PyTuple_New( PyTuple_GET_SIZE( first->terms ) + 1 );
+ if( !terms )
+ return 0;
+ Py_ssize_t end = PyTuple_GET_SIZE( first->terms );
+ for( Py_ssize_t i = 0; i < end; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( first->terms, i );
+ PyTuple_SET_ITEM( terms, i, newref( item ) );
+ }
+ PyTuple_SET_ITEM( terms, end, newref( pyobject_cast( second ) ) );
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
+ expr->terms = terms;
+ expr->constant = first->constant;
+ return pyexpr.release();
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Expression* first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( BinaryMul()( second, 1.0 ) );
+ if( !temp )
+ return 0;
+ return operator()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Expression* first, double second )
+{
+ using namespace PythonHelpers;
+ PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
+ if( !pyexpr )
+ return 0;
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
+ expr->terms = newref( first->terms );
+ expr->constant = first->constant + second;
+ return pyexpr.release();
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Term* first, double second )
+{
+ PythonHelpers::PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
+ if( !pyexpr )
+ return 0;
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
+ expr->constant = second;
+ expr->terms = PyTuple_Pack( 1, first );
+ if( !expr->terms )
+ return 0;
+ return pyexpr.release();
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Term* first, Expression* second )
+{
+ return operator()( second, first );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Term* first, Term* second )
+{
+ PythonHelpers::PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
+ if( !pyexpr )
+ return 0;
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
+ expr->constant = 0.0;
+ expr->terms = PyTuple_Pack( 2, first, second );
+ if( !expr->terms )
+ return 0;
+ return pyexpr.release();
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Term* first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( BinaryMul()( second, 1.0 ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Variable* first, double second )
+{
+ PythonHelpers::PyObjectPtr temp( BinaryMul()( first, 1.0 ) );
+ if( !temp )
+ return 0;
+ return operator()( reinterpret_cast<Term*>( temp.get() ), second );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Variable* first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( BinaryMul()( first, 1.0 ) );
+ if( !temp )
+ return 0;
+ return operator()( reinterpret_cast<Term*>( temp.get() ), second );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Variable* first, Term* second )
+{
+ PythonHelpers::PyObjectPtr temp( BinaryMul()( first, 1.0 ) );
+ if( !temp )
+ return 0;
+ return operator()( reinterpret_cast<Term*>( temp.get() ), second );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( Variable* first, Expression* second )
+{
+ PythonHelpers::PyObjectPtr temp( BinaryMul()( first, 1.0 ) );
+ if( !temp )
+ return 0;
+ return operator()( reinterpret_cast<Term*>( temp.get() ), second );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( double first, Variable* second )
+{
+ return operator()( second, first );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( double first, Term* second )
+{
+ return operator()( second, first );
+}
+
+
+template<> inline
+PyObject* BinaryAdd::operator()( double first, Expression* second )
+{
+ return operator()( second, first );
+}
+
+
+struct BinarySub
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ Py_RETURN_NOTIMPLEMENTED;
+ }
+};
+
+
+template<> inline
+PyObject* BinarySub::operator()( Variable* first, double second )
+{
+ return BinaryAdd()( first, -second );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Variable* first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Variable* first, Term* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Variable* first, Expression* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Expression*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Term* first, double second )
+{
+ return BinaryAdd()( first, -second );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Term* first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Term* first, Term* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Term* first, Expression* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Expression*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Expression* first, double second )
+{
+ return BinaryAdd()( first, -second );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Expression* first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Expression* first, Term* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( Expression* first, Expression* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Expression*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( double first, Variable* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( double first, Term* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
+}
+
+
+template<> inline
+PyObject* BinarySub::operator()( double first, Expression* second )
+{
+ PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
+ if( !temp )
+ return 0;
+ return BinaryAdd()( first, reinterpret_cast<Expression*>( temp.get() ) );
+}
+
+
+template<typename T, typename U>
+PyObject* makecn( T first, U second, kiwi::RelationalOperator op )
+{
+ PythonHelpers::PyObjectPtr pyexpr( BinarySub()( first, second ) );
+ if( !pyexpr )
+ return 0;
+ PythonHelpers::PyObjectPtr pycn( PyType_GenericNew( &Constraint_Type, 0, 0 ) );
+ if( !pycn )
+ return 0;
+ Constraint* cn = reinterpret_cast<Constraint*>( pycn.get() );
+ cn->expression = reduce_expression( pyexpr.get() );
+ if( !cn->expression )
+ return 0;
+ kiwi::Expression expr( convert_to_kiwi_expression( cn->expression ) );
+ new( &cn->constraint ) kiwi::Constraint( expr, op, kiwi::strength::required );
+ return pycn.release();
+}
+
+
+struct CmpEQ
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ return makecn( first, second, kiwi::OP_EQ );
+ }
+};
+
+
+struct CmpLE
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ return makecn( first, second, kiwi::OP_LE );
+ }
+};
+
+
+struct CmpGE
+{
+ template<typename T, typename U>
+ PyObject* operator()( T first, U second )
+ {
+ return makecn( first, second, kiwi::OP_GE );
+ }
+};
diff --git a/contrib/python/kiwisolver/py3/py/term.cpp b/contrib/python/kiwisolver/py3/py/term.cpp
new file mode 100644
index 00000000000..4be64a1eeaf
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/py/term.cpp
@@ -0,0 +1,298 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <sstream>
+#include <Python.h>
+#include "pythonhelpers.h"
+#include "symbolics.h"
+#include "types.h"
+#include "util.h"
+
+
+using namespace PythonHelpers;
+
+
+static PyObject*
+Term_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
+{
+ static const char *kwlist[] = { "variable", "coefficient", 0 };
+ PyObject* pyvar;
+ PyObject* pycoeff = 0;
+ if( !PyArg_ParseTupleAndKeywords(
+ args, kwargs, "O|O:__new__", const_cast<char**>( kwlist ),
+ &pyvar, &pycoeff ) )
+ return 0;
+ if( !Variable::TypeCheck( pyvar ) )
+ return py_expected_type_fail( pyvar, "Variable" );
+ double coefficient = 1.0;
+ if( pycoeff && !convert_to_double( pycoeff, coefficient ) )
+ return 0;
+ PyObject* pyterm = PyType_GenericNew( type, args, kwargs );
+ if( !pyterm )
+ return 0;
+ Term* self = reinterpret_cast<Term*>( pyterm );
+ self->variable = newref( pyvar );
+ self->coefficient = coefficient;
+ return pyterm;
+}
+
+
+static void
+Term_clear( Term* self )
+{
+ Py_CLEAR( self->variable );
+}
+
+
+static int
+Term_traverse( Term* self, visitproc visit, void* arg )
+{
+ Py_VISIT( self->variable );
+ return 0;
+}
+
+
+static void
+Term_dealloc( Term* self )
+{
+ PyObject_GC_UnTrack( self );
+ Term_clear( self );
+ Py_TYPE( self )->tp_free( pyobject_cast( self ) );
+}
+
+
+static PyObject*
+Term_repr( Term* self )
+{
+ std::stringstream stream;
+ stream << self->coefficient << " * ";
+ stream << reinterpret_cast<Variable*>( self->variable )->variable.name();
+ return FROM_STRING( stream.str().c_str() );
+}
+
+
+static PyObject*
+Term_variable( Term* self )
+{
+ return newref( self->variable );
+}
+
+
+static PyObject*
+Term_coefficient( Term* self )
+{
+ return PyFloat_FromDouble( self->coefficient );
+}
+
+
+static PyObject*
+Term_value( Term* self )
+{
+ Variable* pyvar = reinterpret_cast<Variable*>( self->variable );
+ return PyFloat_FromDouble( self->coefficient * pyvar->variable.value() );
+}
+
+
+static PyObject*
+Term_add( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryAdd, Term>()( first, second );
+}
+
+
+static PyObject*
+Term_sub( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinarySub, Term>()( first, second );
+}
+
+
+static PyObject*
+Term_mul( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryMul, Term>()( first, second );
+}
+
+
+static PyObject*
+Term_div( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryDiv, Term>()( first, second );
+}
+
+
+static PyObject*
+Term_neg( PyObject* value )
+{
+ return UnaryInvoke<UnaryNeg, Term>()( value );
+}
+
+
+static PyObject*
+Term_richcmp( PyObject* first, PyObject* second, int op )
+{
+ switch( op )
+ {
+ case Py_EQ:
+ return BinaryInvoke<CmpEQ, Term>()( first, second );
+ case Py_LE:
+ return BinaryInvoke<CmpLE, Term>()( first, second );
+ case Py_GE:
+ return BinaryInvoke<CmpGE, Term>()( first, second );
+ default:
+ break;
+ }
+ PyErr_Format(
+ PyExc_TypeError,
+ "unsupported operand type(s) for %s: "
+ "'%.100s' and '%.100s'",
+ pyop_str( op ),
+ first->ob_type->tp_name,
+ second->ob_type->tp_name
+ );
+ return 0;
+}
+
+
+static PyMethodDef
+Term_methods[] = {
+ { "variable", ( PyCFunction )Term_variable, METH_NOARGS,
+ "Get the variable for the term." },
+ { "coefficient", ( PyCFunction )Term_coefficient, METH_NOARGS,
+ "Get the coefficient for the term." },
+ { "value", ( PyCFunction )Term_value, METH_NOARGS,
+ "Get the value for the term." },
+ { 0 } // sentinel
+};
+
+
+static PyNumberMethods
+Term_as_number = {
+ (binaryfunc)Term_add, /* nb_add */
+ (binaryfunc)Term_sub, /* nb_subtract */
+ (binaryfunc)Term_mul, /* nb_multiply */
+#if PY_MAJOR_VERSION < 3
+ (binaryfunc)Term_div, /* nb_divide */
+#endif
+ 0, /* nb_remainder */
+ 0, /* nb_divmod */
+ 0, /* nb_power */
+ (unaryfunc)Term_neg, /* nb_negative */
+ 0, /* nb_positive */
+ 0, /* nb_absolute */
+#if PY_MAJOR_VERSION >= 3
+ 0, /* nb_bool */
+#else
+ 0, /* nb_nonzero */
+#endif
+ 0, /* nb_invert */
+ 0, /* nb_lshift */
+ 0, /* nb_rshift */
+ 0, /* nb_and */
+ 0, /* nb_xor */
+ (binaryfunc)0, /* nb_or */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_coerce */
+#endif
+ 0, /* nb_int */
+ 0, /* nb_long */
+ 0, /* nb_float */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_oct */
+ 0, /* nb_hex */
+#endif
+ 0, /* nb_inplace_add */
+ 0, /* nb_inplace_subtract */
+ 0, /* nb_inplace_multiply */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_inplace_divide */
+#endif
+ 0, /* nb_inplace_remainder */
+ 0, /* nb_inplace_power */
+ 0, /* nb_inplace_lshift */
+ 0, /* nb_inplace_rshift */
+ 0, /* nb_inplace_and */
+ 0, /* nb_inplace_xor */
+ 0, /* nb_inplace_or */
+ (binaryfunc)0, /* nb_floor_divide */
+ (binaryfunc)Term_div, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+#if PY_VERSION_HEX >= 0x02050000
+ (unaryfunc)0, /* nb_index */
+#endif
+#if PY_VERSION_HEX >= 0x03050000
+ (binaryfunc)0, /* nb_matrix_multiply */
+ (binaryfunc)0, /* nb_inplace_matrix_multiply */
+#endif
+};
+
+
+PyTypeObject Term_Type = {
+ PyVarObject_HEAD_INIT( &PyType_Type, 0 )
+ "kiwisolver.Term", /* tp_name */
+ sizeof( Term ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Term_dealloc, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03050000
+ ( PyAsyncMethods* )0, /* tp_as_async */
+#elif PY_VERSION_HEX >= 0x03000000
+ ( void* ) 0, /* tp_reserved */
+#else
+ ( cmpfunc )0, /* tp_compare */
+#endif
+ (reprfunc)Term_repr, /* tp_repr */
+ (PyNumberMethods*)&Term_as_number, /* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+#if PY_MAJOR_VERSION >= 3
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, /* tp_flags */
+#else
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+#endif
+ 0, /* Documentation string */
+ (traverseproc)Term_traverse, /* tp_traverse */
+ (inquiry)Term_clear, /* tp_clear */
+ (richcmpfunc)Term_richcmp, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)Term_methods, /* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)Term_new, /* tp_new */
+ (freefunc)PyObject_GC_Del, /* tp_free */
+ (inquiry)0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ (destructor)0 /* tp_del */
+};
+
+
+int import_term()
+{
+ return PyType_Ready( &Term_Type );
+}
diff --git a/contrib/python/kiwisolver/py3/py/types.h b/contrib/python/kiwisolver/py3/py/types.h
new file mode 100644
index 00000000000..628efafbca4
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/py/types.h
@@ -0,0 +1,112 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <Python.h>
+#include <kiwi/kiwi.h>
+
+
+int import_variable();
+
+int import_term();
+
+int import_expression();
+
+int import_constraint();
+
+int import_solver();
+
+int import_strength();
+
+
+extern PyTypeObject Variable_Type;
+
+extern PyTypeObject Term_Type;
+
+extern PyTypeObject Expression_Type;
+
+extern PyTypeObject Constraint_Type;
+
+extern PyTypeObject Solver_Type;
+
+extern PyTypeObject strength_Type;
+
+extern PyObject* DuplicateConstraint;
+
+extern PyObject* UnsatisfiableConstraint;
+
+extern PyObject* UnknownConstraint;
+
+extern PyObject* DuplicateEditVariable;
+
+extern PyObject* UnknownEditVariable;
+
+extern PyObject* BadRequiredStrength;
+
+
+struct Variable
+{
+ PyObject_HEAD
+ PyObject* context;
+ kiwi::Variable variable;
+
+ static bool TypeCheck( PyObject* obj )
+ {
+ return PyObject_TypeCheck( obj, &Variable_Type ) != 0;
+ }
+};
+
+
+struct Term
+{
+ PyObject_HEAD
+ PyObject* variable;
+ double coefficient;
+
+ static bool TypeCheck( PyObject* obj )
+ {
+ return PyObject_TypeCheck( obj, &Term_Type ) != 0;
+ }
+};
+
+
+struct Expression
+{
+ PyObject_HEAD
+ PyObject* terms;
+ double constant;
+
+ static bool TypeCheck( PyObject* obj )
+ {
+ return PyObject_TypeCheck( obj, &Expression_Type ) != 0;
+ }
+};
+
+
+struct Constraint
+{
+ PyObject_HEAD
+ PyObject* expression;
+ kiwi::Constraint constraint;
+
+ static bool TypeCheck( PyObject* obj )
+ {
+ return PyObject_TypeCheck( obj, &Constraint_Type ) != 0;
+ }
+};
+
+
+struct Solver
+{
+ PyObject_HEAD
+ kiwi::Solver solver;
+
+ static bool TypeCheck( PyObject* obj )
+ {
+ return PyObject_TypeCheck( obj, &Solver_Type ) != 0;
+ }
+};
diff --git a/contrib/python/kiwisolver/py3/py/util.h b/contrib/python/kiwisolver/py3/py/util.h
new file mode 100644
index 00000000000..78e9cbd0b8e
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/py/util.h
@@ -0,0 +1,230 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#pragma once
+#include <map>
+#include <string>
+#include <Python.h>
+#include <kiwi/kiwi.h>
+#include "pythonhelpers.h"
+#include "types.h"
+
+
+inline bool
+convert_to_double( PyObject* obj, double& out )
+{
+ if( PyFloat_Check( obj ) )
+ {
+ out = PyFloat_AS_DOUBLE( obj );
+ return true;
+ }
+#if PY_MAJOR_VERSION < 3
+ if( PyInt_Check( obj ) )
+ {
+ out = double( PyInt_AsLong( obj ) );
+ return true;
+ }
+#endif
+ if( PyLong_Check( obj ) )
+ {
+ out = PyLong_AsDouble( obj );
+ if( out == -1.0 && PyErr_Occurred() )
+ return false;
+ return true;
+ }
+ PythonHelpers::py_expected_type_fail( obj, "float, int, or long" );
+ return false;
+}
+
+
+inline bool
+convert_pystr_to_str( PyObject* value, std::string& out )
+{
+#if PY_MAJOR_VERSION >= 3
+ out = PyUnicode_AsUTF8( value );
+#else
+ if( PyUnicode_Check( value ) )
+ {
+ PythonHelpers::PyObjectPtr py_str( PyUnicode_AsUTF8String( value ) );
+ if( !py_str )
+ return false; // LCOV_EXCL_LINE
+ out = PyString_AS_STRING( py_str.get() );
+ }
+ else
+ out = PyString_AS_STRING( value );
+#endif
+ return true;
+}
+
+
+inline bool
+convert_to_strength( PyObject* value, double& out )
+{
+#if PY_MAJOR_VERSION >= 3
+ if( PyUnicode_Check( value ) )
+ {
+#else
+ if( PyString_Check( value ) | PyUnicode_Check( value ))
+ {
+#endif
+ std::string str;
+ if( !convert_pystr_to_str( value, str ) )
+ return false;
+ if( str == "required" )
+ out = kiwi::strength::required;
+ else if( str == "strong" )
+ out = kiwi::strength::strong;
+ else if( str == "medium" )
+ out = kiwi::strength::medium;
+ else if( str == "weak" )
+ out = kiwi::strength::weak;
+ else
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "string strength must be 'required', 'strong', 'medium', "
+ "or 'weak', not '%s'",
+ str.c_str()
+ );
+ return false;
+ }
+ return true;
+ }
+ if( !convert_to_double( value, out ) )
+ return false;
+ return true;
+}
+
+
+inline bool
+convert_to_relational_op( PyObject* value, kiwi::RelationalOperator& out )
+{
+#if PY_MAJOR_VERSION >= 3
+ if( !PyUnicode_Check( value ) )
+ {
+ PythonHelpers::py_expected_type_fail( value, "unicode" );
+ return false;
+ }
+#else
+ if( !(PyString_Check( value ) | PyUnicode_Check( value ) ) )
+ {
+ PythonHelpers::py_expected_type_fail( value, "str or unicode" );
+ return false;
+ }
+#endif
+ std::string str;
+ if( !convert_pystr_to_str( value, str ) )
+ return false;
+ if( str == "==" )
+ out = kiwi::OP_EQ;
+ else if( str == "<=" )
+ out = kiwi::OP_LE;
+ else if( str == ">=" )
+ out = kiwi::OP_GE;
+ else
+ {
+ PyErr_Format(
+ PyExc_ValueError,
+ "relational operator must be '==', '<=', or '>=', not '%s'",
+ str.c_str()
+ );
+ return false;
+ }
+ return true;
+}
+
+
+inline PyObject*
+make_terms( const std::map<PyObject*, double>& coeffs )
+{
+ typedef std::map<PyObject*, double>::const_iterator iter_t;
+ PythonHelpers::PyObjectPtr terms( PyTuple_New( coeffs.size() ) );
+ if( !terms )
+ return 0;
+ Py_ssize_t size = PyTuple_GET_SIZE( terms.get() );
+ for( Py_ssize_t i = 0; i < size; ++i ) // zero tuple for safe early return
+ PyTuple_SET_ITEM( terms.get(), i, 0 );
+ Py_ssize_t i = 0;
+ iter_t it = coeffs.begin();
+ iter_t end = coeffs.end();
+ for( ; it != end; ++it, ++i )
+ {
+ PyObject* pyterm = PyType_GenericNew( &Term_Type, 0, 0 );
+ if( !pyterm )
+ return 0;
+ Term* term = reinterpret_cast<Term*>( pyterm );
+ term->variable = PythonHelpers::newref( it->first );
+ term->coefficient = it->second;
+ PyTuple_SET_ITEM( terms.get(), i, pyterm );
+ }
+ return terms.release();
+}
+
+
+inline PyObject*
+reduce_expression( PyObject* pyexpr ) // pyexpr must be an Expression
+{
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr );
+ std::map<PyObject*, double> coeffs;
+ Py_ssize_t size = PyTuple_GET_SIZE( expr->terms );
+ for( Py_ssize_t i = 0; i < size; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( expr->terms, i );
+ Term* term = reinterpret_cast<Term*>( item );
+ coeffs[ term->variable ] += term->coefficient;
+ }
+ PythonHelpers::PyObjectPtr terms( make_terms( coeffs ) );
+ if( !terms )
+ return 0;
+ PyObject* pynewexpr = PyType_GenericNew( &Expression_Type, 0, 0 );
+ if( !pynewexpr )
+ return 0;
+ Expression* newexpr = reinterpret_cast<Expression*>( pynewexpr );
+ newexpr->terms = terms.release();
+ newexpr->constant = expr->constant;
+ return pynewexpr;
+}
+
+
+inline kiwi::Expression
+convert_to_kiwi_expression( PyObject* pyexpr ) // pyexpr must be an Expression
+{
+ Expression* expr = reinterpret_cast<Expression*>( pyexpr );
+ std::vector<kiwi::Term> kterms;
+ Py_ssize_t size = PyTuple_GET_SIZE( expr->terms );
+ for( Py_ssize_t i = 0; i < size; ++i )
+ {
+ PyObject* item = PyTuple_GET_ITEM( expr->terms, i );
+ Term* term = reinterpret_cast<Term*>( item );
+ Variable* var = reinterpret_cast<Variable*>( term->variable );
+ kterms.push_back( kiwi::Term( var->variable, term->coefficient ) );
+ }
+ return kiwi::Expression( kterms, expr->constant );
+}
+
+
+inline const char*
+pyop_str( int op )
+{
+ switch( op )
+ {
+ case Py_LT:
+ return "<";
+ case Py_LE:
+ return "<=";
+ case Py_EQ:
+ return "==";
+ case Py_NE:
+ return "!=";
+ case Py_GT:
+ return ">";
+ case Py_GE:
+ return ">=";
+ default:
+ return "";
+ }
+}
diff --git a/contrib/python/kiwisolver/py3/py/variable.cpp b/contrib/python/kiwisolver/py3/py/variable.cpp
new file mode 100644
index 00000000000..a622e8529ab
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/py/variable.cpp
@@ -0,0 +1,353 @@
+/*-----------------------------------------------------------------------------
+| Copyright (c) 2013-2017, Nucleic Development Team.
+|
+| Distributed under the terms of the Modified BSD License.
+|
+| The full license is in the file COPYING.txt, distributed with this software.
+|----------------------------------------------------------------------------*/
+#include <Python.h>
+#include <kiwi/kiwi.h>
+#include "pythonhelpers.h"
+#include "symbolics.h"
+#include "types.h"
+#include "util.h"
+
+
+using namespace PythonHelpers;
+
+
+static PyObject*
+Variable_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
+{
+ static const char *kwlist[] = { "name", "context", 0 };
+ PyObject* context = 0;
+ PyObject* name = 0;
+
+ if( !PyArg_ParseTupleAndKeywords(
+ args, kwargs, "|OO:__new__", const_cast<char**>( kwlist ),
+ &name, &context ) )
+ return 0;
+
+ PyObjectPtr pyvar( PyType_GenericNew( type, args, kwargs ) );
+ if( !pyvar )
+ return 0;
+
+ Variable* self = reinterpret_cast<Variable*>( pyvar.get() );
+ self->context = xnewref( context );
+
+ if( name != 0 )
+ {
+#if PY_MAJOR_VERSION >= 3
+ if( !PyUnicode_Check( name ) )
+ return py_expected_type_fail( name, "unicode" );
+#else
+ if( !( PyString_Check( name ) | PyUnicode_Check( name ) ) )
+ {
+ return py_expected_type_fail( name, "str or unicode" );
+ }
+#endif
+ std::string c_name;
+ if( !convert_pystr_to_str(name, c_name) )
+ return 0; // LCOV_EXCL_LINE
+ new( &self->variable ) kiwi::Variable( c_name );
+ }
+ else
+ {
+ new( &self->variable ) kiwi::Variable();
+ }
+
+ return pyvar.release();
+}
+
+
+static void
+Variable_clear( Variable* self )
+{
+ Py_CLEAR( self->context );
+}
+
+
+static int
+Variable_traverse( Variable* self, visitproc visit, void* arg )
+{
+ Py_VISIT( self->context );
+ return 0;
+}
+
+
+static void
+Variable_dealloc( Variable* self )
+{
+ PyObject_GC_UnTrack( self );
+ Variable_clear( self );
+ self->variable.~Variable();
+ Py_TYPE( self )->tp_free( pyobject_cast( self ) );
+}
+
+
+static PyObject*
+Variable_repr( Variable* self )
+{
+ return FROM_STRING( self->variable.name().c_str() );
+}
+
+
+static PyObject*
+Variable_name( Variable* self )
+{
+ return FROM_STRING( self->variable.name().c_str() );
+}
+
+
+static PyObject*
+Variable_setName( Variable* self, PyObject* pystr )
+{
+#if PY_MAJOR_VERSION >= 3
+ if( !PyUnicode_Check( pystr ) )
+ return py_expected_type_fail( pystr, "unicode" );
+#else
+ if( !(PyString_Check( pystr ) | PyUnicode_Check( pystr ) ) )
+ {
+ return py_expected_type_fail( pystr, "str or unicode" );
+ }
+#endif
+ std::string str;
+ if( !convert_pystr_to_str( pystr, str ) )
+ return 0;
+ self->variable.setName( str );
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Variable_context( Variable* self )
+{
+ if( self->context )
+ return newref( self->context );
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Variable_setContext( Variable* self, PyObject* value )
+{
+ if( value != self->context )
+ {
+ PyObject* temp = self->context;
+ self->context = newref( value );
+ Py_XDECREF( temp );
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject*
+Variable_value( Variable* self )
+{
+ return PyFloat_FromDouble( self->variable.value() );
+}
+
+
+static PyObject*
+Variable_add( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryAdd, Variable>()( first, second );
+}
+
+
+static PyObject*
+Variable_sub( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinarySub, Variable>()( first, second );
+}
+
+
+static PyObject*
+Variable_mul( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryMul, Variable>()( first, second );
+}
+
+
+static PyObject*
+Variable_div( PyObject* first, PyObject* second )
+{
+ return BinaryInvoke<BinaryDiv, Variable>()( first, second );
+}
+
+
+static PyObject*
+Variable_neg( PyObject* value )
+{
+ return UnaryInvoke<UnaryNeg, Variable>()( value );
+}
+
+
+static PyObject*
+Variable_richcmp( PyObject* first, PyObject* second, int op )
+{
+ switch( op )
+ {
+ case Py_EQ:
+ return BinaryInvoke<CmpEQ, Variable>()( first, second );
+ case Py_LE:
+ return BinaryInvoke<CmpLE, Variable>()( first, second );
+ case Py_GE:
+ return BinaryInvoke<CmpGE, Variable>()( first, second );
+ default:
+ break;
+ }
+ PyErr_Format(
+ PyExc_TypeError,
+ "unsupported operand type(s) for %s: "
+ "'%.100s' and '%.100s'",
+ pyop_str( op ),
+ first->ob_type->tp_name,
+ second->ob_type->tp_name
+ );
+ return 0;
+}
+
+
+static PyMethodDef
+Variable_methods[] = {
+ { "name", ( PyCFunction )Variable_name, METH_NOARGS,
+ "Get the name of the variable." },
+ { "setName", ( PyCFunction )Variable_setName, METH_O,
+ "Set the name of the variable." },
+ { "context", ( PyCFunction )Variable_context, METH_NOARGS,
+ "Get the context object associated with the variable." },
+ { "setContext", ( PyCFunction )Variable_setContext, METH_O,
+ "Set the context object associated with the variable." },
+ { "value", ( PyCFunction )Variable_value, METH_NOARGS,
+ "Get the current value of the variable." },
+ { 0 } // sentinel
+};
+
+
+static PyNumberMethods
+Variable_as_number = {
+ (binaryfunc)Variable_add, /* nb_add */
+ (binaryfunc)Variable_sub, /* nb_subtract */
+ (binaryfunc)Variable_mul, /* nb_multiply */
+#if PY_MAJOR_VERSION < 3
+ (binaryfunc)Variable_div, /* nb_divide */
+#endif
+ 0, /* nb_remainder */
+ 0, /* nb_divmod */
+ 0, /* nb_power */
+ (unaryfunc)Variable_neg, /* nb_negative */
+ 0, /* nb_positive */
+ 0, /* nb_absolute */
+#if PY_MAJOR_VERSION >= 3
+ 0, /* nb_bool */
+#else
+ 0, /* nb_nonzero */
+#endif
+ 0, /* nb_invert */
+ 0, /* nb_lshift */
+ 0, /* nb_rshift */
+ 0, /* nb_and */
+ 0, /* nb_xor */
+ (binaryfunc)0, /* nb_or */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_coerce */
+#endif
+ 0, /* nb_int */
+ 0, /* nb_long */
+ 0, /* nb_float */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_oct */
+ 0, /* nb_hex */
+#endif
+ 0, /* nb_inplace_add */
+ 0, /* nb_inplace_subtract */
+ 0, /* nb_inplace_multiply */
+#if PY_MAJOR_VERSION < 3
+ 0, /* nb_inplace_divide */
+#endif
+ 0, /* nb_inplace_remainder */
+ 0, /* nb_inplace_power */
+ 0, /* nb_inplace_lshift */
+ 0, /* nb_inplace_rshift */
+ 0, /* nb_inplace_and */
+ 0, /* nb_inplace_xor */
+ 0, /* nb_inplace_or */
+ (binaryfunc)0, /* nb_floor_divide */
+ (binaryfunc)Variable_div, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+#if PY_VERSION_HEX >= 0x02050000
+ (unaryfunc)0, /* nb_index */
+#endif
+#if PY_VERSION_HEX >= 0x03050000
+ (binaryfunc)0, /* nb_matrix_multiply */
+ (binaryfunc)0, /* nb_inplace_matrix_multiply */
+#endif
+};
+
+
+PyTypeObject Variable_Type = {
+ PyVarObject_HEAD_INIT( &PyType_Type, 0 )
+ "kiwisolver.Variable", /* tp_name */
+ sizeof( Variable ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Variable_dealloc, /* tp_dealloc */
+ (printfunc)0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+#if PY_VERSION_HEX >= 0x03050000
+ ( PyAsyncMethods* )0, /* tp_as_async */
+#elif PY_VERSION_HEX >= 0x03000000
+ ( void* ) 0, /* tp_reserved */
+#else
+ ( cmpfunc )0, /* tp_compare */
+#endif
+ (reprfunc)Variable_repr, /* tp_repr */
+ (PyNumberMethods*)&Variable_as_number, /* tp_as_number */
+ (PySequenceMethods*)0, /* tp_as_sequence */
+ (PyMappingMethods*)0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ (getattrofunc)0, /* tp_getattro */
+ (setattrofunc)0, /* tp_setattro */
+ (PyBufferProcs*)0, /* tp_as_buffer */
+#if PY_MAJOR_VERSION >= 3
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE, /* tp_flags */
+#else
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+#endif
+ 0, /* Documentation string */
+ (traverseproc)Variable_traverse, /* tp_traverse */
+ (inquiry)Variable_clear, /* tp_clear */
+ (richcmpfunc)Variable_richcmp, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)0, /* tp_iter */
+ (iternextfunc)0, /* tp_iternext */
+ (struct PyMethodDef*)Variable_methods, /* tp_methods */
+ (struct PyMemberDef*)0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ (descrgetfunc)0, /* tp_descr_get */
+ (descrsetfunc)0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)PyType_GenericAlloc, /* tp_alloc */
+ (newfunc)Variable_new, /* tp_new */
+ (freefunc)PyObject_GC_Del, /* tp_free */
+ (inquiry)0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ (destructor)0 /* tp_del */
+};
+
+
+int import_variable()
+{
+ return PyType_Ready( &Variable_Type );
+}
diff --git a/contrib/python/kiwisolver/py3/ya.make b/contrib/python/kiwisolver/py3/ya.make
new file mode 100644
index 00000000000..b98f8485dc0
--- /dev/null
+++ b/contrib/python/kiwisolver/py3/ya.make
@@ -0,0 +1,41 @@
+# Generated by devtools/yamaker (pypi).
+
+PY3_LIBRARY()
+
+VERSION(1.1.0)
+
+LICENSE(BSD-3-Clause)
+
+PEERDIR(
+ contrib/python/setuptools
+)
+
+ADDINCL(
+ contrib/python/kiwisolver/py3
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_LINT()
+
+SRCS(
+ py/constraint.cpp
+ py/expression.cpp
+ py/kiwisolver.cpp
+ py/solver.cpp
+ py/strength.cpp
+ py/term.cpp
+ py/variable.cpp
+)
+
+PY_REGISTER(
+ kiwisolver
+)
+
+RESOURCE_FILES(
+ PREFIX contrib/python/kiwisolver/py3/
+ .dist-info/METADATA
+ .dist-info/top_level.txt
+)
+
+END()
diff --git a/contrib/python/kiwisolver/ya.make b/contrib/python/kiwisolver/ya.make
new file mode 100644
index 00000000000..773d6b13bb0
--- /dev/null
+++ b/contrib/python/kiwisolver/ya.make
@@ -0,0 +1,18 @@
+PY23_LIBRARY()
+
+LICENSE(Service-Py23-Proxy)
+
+IF (PYTHON2)
+ PEERDIR(contrib/python/kiwisolver/py2)
+ELSE()
+ PEERDIR(contrib/python/kiwisolver/py3)
+ENDIF()
+
+NO_LINT()
+
+END()
+
+RECURSE(
+ py2
+ py3
+)