Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

create workflow ci #6

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/pythonapp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Python application

on: push

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up Python 3.6
uses: actions/setup-python@v1
with:
python-version: 3.6
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Lint with flake8
run: |
pip install flake8
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82,F401,E711,F403,F841 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pip install pytest
# pytest
python setup.py test
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

pyquat is a Python C extension providing quaternions and functions relating to simulation of attitudes and rotations.

![build schtatus](https://github.com/openlunar/pyquat/workflows/Python%20application/badge.svg)
[![Build Status](https://travis-ci.org/mohawkjohn/pyquat.svg?branch=master)](https://travis-ci.org/mohawkjohn/pyquat)

## Installation
Expand Down Expand Up @@ -29,4 +30,4 @@ pyquat is a Python C extension providing quaternions and functions relating to s

Copyright 2016--2017 John O. Woods, Ph.D., and Intuitive Machines.

See LICENSE.txt.
See LICENSE.txt.
29 changes: 16 additions & 13 deletions pyquat/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
from _pyquat import *

import math
from _pyquat import Quat, expm, big_omega, skew
from _pyquat import valenti_q_mag, valenti_q_acc
from _pyquat import rotation_vector_to_matrix
from _pyquat import identity


import numpy as np
from scipy import linalg
import warnings

QUAT_SMALL = 1e-8


def touch():
"""Touch all imports from cython to alleviate flake8."""
if valenti_q_acc == valenti_q_mag:
print(rotation_vector_to_matrix)
identity(valenti_q_mag)
raise Exception("Never run this")
Comment on lines +14 to +19
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not clear on what this does.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an abomination to use the things imported from the _pyquat. I regret it already, but I'm not sure how to do this any better.

Unused imports are bad, but the unused imports here are kinda-sorta necessary to load the context for the other things downrange that use this init as the conduit into the cython.

Cython itself didn't have any particularly clear patterns on how to explicitly import without leaving unused imports, or having unclear context.



def fromstring(*args, **kwargs):
"""
Shortcut for pyquat.Quat.from_vector(numpy.fromstring()). If you
Expand Down Expand Up @@ -139,7 +150,7 @@ def mean(ary, covariance = None):

This method takes a 4xN array and computes the average using eigenvalue decomposition.
"""
if covariance == None:
if covariance is None:
covariance = cov(ary)

# Compute their eigenvalues and eigenvectors
Expand Down Expand Up @@ -278,9 +289,6 @@ def step_cg3(
A21 = 0.75
A31 = 119/216.0
A32 = 17/108.0
C1 = 0.0
C2 = 3/4.0
C3 = 17/24.0

q1 = q.to_vector()

Expand Down Expand Up @@ -351,11 +359,6 @@ def step_cg4(
A52 = 0.2390958372307326
A53 = 1.3918565724203246
A54 = -1.1092979392113565
C1 = 0.0
C2 = 0.8177227988124852
C3 = 0.3859740639032449
C4 = 0.3242290522866937
C5 = 0.8768903263420429

q1 = q.to_vector()

Expand All @@ -370,7 +373,7 @@ def step_cg4(

else:
if J is None:
J = numpy.identity(3)
J = np.identity(3)
J_inv = J
elif J_inv is None:
J_inv = linalg.inv(J)
Expand Down
62 changes: 32 additions & 30 deletions pyquat/plot.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,36 @@
import numpy as np
import numpy
import matplotlib.pyplot
from mpl_toolkits.mplot3d import Axes3D


def prepare_quaternion_array_for_plotting(q_ary, rotate_axis='x'):
""" Converting all attitudes to points on a sphere """
"""Converting all attitudes to points on a sphere."""
ary = None
if len(q_ary.shape) == 1:
ary = numpy.empty((3, q_ary.shape[0]))
for i, q in enumerate(q_ary):
ary[:,i] = q.to_unit_vector(rotate_axis)[:,0]
ary[:, i] = q.to_unit_vector(rotate_axis)[:, 0]
elif len(q_ary.shape) == 2:
ary = numpy.empty((3, q_ary.shape[1]))
for i, q in enumerate(q_ary):
ary[:,i] = q[0].to_unit_vector(rotate_axis)[:,0]
ary[:, i] = q[0].to_unit_vector(rotate_axis)[:, 0]
else:
raise InputError("expected 1- or 2-D array")
raise Exception("expected 1- or 2-D array")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a ValueError.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair I couldn't find a deceleration for InputError. I'll change these. I too dislike base Exceptions.

return ary


def scatter(q_ary, rotate_axis='x', fig = None, axes = None, **kwargs):
""" Plot an array of quaternions as scatter points on a sphere """

def scatter(q_ary, rotate_axis='x', fig=None, axes=None, **kwargs):
"""Plot an array of quaternions as scatter points on a sphere."""
if fig is None:
fig = matplotlib.pyplot.figure()
if axes is None:
axes = fig.add_subplot(111, projection='3d')

ary = prepare_quaternion_array_for_plotting(q_ary, rotate_axis = rotate_axis)
ary = prepare_quaternion_array_for_plotting(q_ary, rotate_axis=rotate_axis)

return axes.scatter(ary[0,:], ary[1,:], ary[2,:], **kwargs)
return axes.scatter(ary[0, :], ary[1, :], ary[2, :], **kwargs)


def plot(q_ary, t = None, rotate_axis='x', fig = None, axes = None, **kwargs):
def plot(q_ary, t=None, rotate_axis='x', fig=None, axes=None, **kwargs):
"""
Plot an array of quaternions using lines on the surface of a sphere.

Expand All @@ -41,7 +39,6 @@ def plot(q_ary, t = None, rotate_axis='x', fig = None, axes = None, **kwargs):
displayed blue.

"""

if fig is None:
fig = matplotlib.pyplot.figure()
if axes is None:
Expand All @@ -53,14 +50,19 @@ def plot(q_ary, t = None, rotate_axis='x', fig = None, axes = None, **kwargs):
tc = (t - t.min()) / (t.max() - t.min())
c = numpy.vstack((tc, numpy.zeros_like(tc), -tc + 1.0))

for i in range(1,ary.shape[1]):
axes.plot(ary[0,i-1:i+1], ary[1,i-1:i+1], ary[2,i-1:i+1], c = tuple(c[:,i]), **kwargs)
for i in range(1, ary.shape[1]):
axes.plot(ary[0, i - 1:i + 1],
ary[1, i - 1:i + 1],
ary[2, i - 1:i + 1],
c=tuple(c[:, i]), **kwargs)
Comment on lines -56 to +57
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love this type of change. It's going to make some code absolutely unreadable. I realize that expressions should be space-separated in general, but these are expressions within bracket notation.

else:
return axes.plot(ary[0,:], ary[1,:], ary[2,:], **kwargs)
return axes.plot(ary[0, :], ary[1, :], ary[2, :], **kwargs)


def plot_frame(q, r = numpy.zeros((3,1)), fig = None, axes = None, axis_size = 1.0):
def plot_frame(q, r=numpy.zeros((3, 1)), fig=None, axes=None, axis_size=1.0):
"""
Plot a quaternion as a coordinate frame, with red, green, and blue
Plot a quaternion as a coordinate frame, with red, green, and blue.

referring to x, y, and z.

Also accepts an optional position to move the frame to (post-rotation).
Expand All @@ -70,21 +72,21 @@ def plot_frame(q, r = numpy.zeros((3,1)), fig = None, axes = None, axis_size = 1
if axes is None:
axes = fig.add_subplot(111, projection='3d')

xh = numpy.zeros((3,2))
xh = numpy.zeros((3, 2))
yh = numpy.zeros_like(xh)
zh = numpy.zeros_like(xh)
xh[0,1] = axis_size
yh[1,1] = axis_size
zh[2,1] = axis_size
xh[0, 1] = axis_size
yh[1, 1] = axis_size
zh[2, 1] = axis_size
Comment on lines -73 to +80
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as with the array indexing. I don't think this change substantially improves readability.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I'm going to push back on the second part of this one a bit more because it doesn't actually appear in pep8: https://stackoverflow.com/questions/31741418/pep8-space-after-a-comma/37064013#37064013

I think there should be spaces after commas except within array notation. The examples in pep8 do show spaces after commas, even though this isn't specifically enumerated; but they don't show multi-dimensional array indexing notation.

Thoughts?


# Transform the frame (rotate it and then move it)
T = q.to_matrix()
txh = np.dot(T, xh) + r
tyh = np.dot(T, yh) + r
tzh = np.dot(T, zh) + r
axes.plot(txh[0,:], txh[1,:], txh[2,:], c='r')
axes.plot(tyh[0,:], tyh[1,:], tyh[2,:], c='g')
axes.plot(tzh[0,:], tzh[1,:], tzh[2,:], c='b')
txh = numpy.dot(T, xh) + r
tyh = numpy.dot(T, yh) + r
tzh = numpy.dot(T, zh) + r

axes.plot(txh[0, :], txh[1, :], txh[2, :], c='r')
axes.plot(tyh[0, :], tyh[1, :], tyh[2, :], c='g')
axes.plot(tzh[0, :], tzh[1, :], tzh[2, :], c='b')

return axes
15 changes: 6 additions & 9 deletions pyquat/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,18 @@
from math import sqrt, cos, sin, pi
import numpy as np

def randu(symmetric_range = 1.0):

def randu(symmetric_range=1.0):
"""
Generate a uniform random number with mean 0 and range
(-symmetric_range, +symmetric_range). Default argument (1.0)
gives mean 0 and range (-1, 1).
"""

return (np.random.rand() * 2.0 - 1.0) * symmetric_range

def uniform_random_axis(max_theta = 2.0 * pi, z_range = 1.0):
"""
Generate a unit random axis from a uniform distribution.
"""

def uniform_random_axis(max_theta=2.0 * pi, z_range=1.0):
"""Generate a unit random axis from a uniform distribution."""
if max_theta == 0.0:
theta = 0.0
else:
Expand Down Expand Up @@ -55,11 +54,9 @@ def rand(

"""
if axis is not None and angle is not None:
raise StandardError("expected non-fixed angle or non-fixed axis or both")
raise Exception("expected non-fixed angle or non-fixed axis or both")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raise Exception("expected non-fixed angle or non-fixed axis or both")
raise ValueError("expected non-fixed angle or non-fixed axis or both")

if axis is None:
axis = axis_generator(**axis_generator_kwargs)
if angle is None:
angle = angle_generator()
return pq.Quat.from_angle_axis(angle, *axis)


7 changes: 1 addition & 6 deletions pyquat/wahba/esoq.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import numpy as np
from scipy import linalg
from math import sqrt, pi, cos, acos
from math import sqrt, cos, acos

def trace_adj(a):
if max(a.shape) == 3:
Expand Down Expand Up @@ -219,11 +219,6 @@ def davenport_eigenvalues(K = None, B = None, tr_B = None, tr_adj_K = None, tr_K
tr_adj_S = trace_adj_symm(S)
if z is None:
z = K[1:4,0].reshape((3,1))

if tr_K is None:
a = np.trace(K)
else:
a = tr_K

b = -2.0 * tr_B**2 + tr_adj_S - np.dot(z.T, z)[0,0]
d = linalg.det(K)
Expand Down
9 changes: 2 additions & 7 deletions pyquat/wahba/valenti.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,10 @@

"""

import numpy as np
from math import sqrt

from pyquat import valenti_q_mag as q_mag
from pyquat import valenti_q_acc as q_acc
from pyquat import valenti_dq_mag as dq_mag
from pyquat import valenti_dq_acc as dq_acc




def q_global_to_local(a, b):
"""Compute a global to local transformation using a relatively
low-noise measurement a (e.g. from an accelerometer) and a
Expand Down
17 changes: 8 additions & 9 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,22 @@
https://github.com/mohawkjohn/pyquat
"""

from setuptools import setup, find_packages
from setuptools import setup
from setuptools.extension import Extension
import os
import numpy

MAJOR = 0
MINOR = 3
TINY = 3
version='%d.%d.%d' % (MAJOR, MINOR, TINY)
TINY = 3
version = '%d.%d.%d' % (MAJOR, MINOR, TINY)

c_quat = Extension('_pyquat',
['pyquat/pyquat.c'],
extra_compile_args = ["-std=c99"],
include_dirs = [numpy.get_include()],
define_macros = [('MAJOR_VERSION', MAJOR),
('MINOR_VERSION', MINOR),
('TINY_VERSION', TINY)])
extra_compile_args=["-std=c99"],
include_dirs=[numpy.get_include()],
define_macros=[('MAJOR_VERSION', MAJOR),
('MINOR_VERSION', MINOR),
('TINY_VERSION', TINY)])
setup(name='pyquat',
version=version,
description='Python C quaternion type for fast attitude and rotation computations',
Expand Down
5 changes: 3 additions & 2 deletions test/assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
import numpy as np
import math

from .context import pq
from .context import pq_esoq

import pyquat.wahba.esoq as pq_esoq
import pyquat as pq

class QuaternionTest(unittest.TestCase):
def assert_almost_equal_components(self, q1, q2, **kwargs):
Expand Down
16 changes: 8 additions & 8 deletions test/context.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

import pyquat as pq
import pyquat.wahba.esoq as pq_esoq
import pyquat.random as pqr
from pyquat import Quat
# import os
# import sys
# sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
#
# import pyquat as pq
# import pyquat.wahba.esoq as pq_esoq
# import pyquat.random as pqr
# from pyquat import Quat
Loading