Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import requests\n",
"from requests.auth import HTTPBasicAuth\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"request_content = {\n",
" 'index_one': 1,\n",
" 'index_two': 2,\n",
" 'array': [[1, 2, 3], [4, 5, 6], [7, 8, 9]]\n",
"}\n",
"\n",
"resp = requests.get(\n",
" 'http://localhost:5000/row_interchange',\n",
" auth=HTTPBasicAuth('example_user', 'example_password'),\n",
" json=request_content\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1., 2., 3.],\n",
" [7., 8., 9.],\n",
" [4., 5., 6.]])"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.array(resp.json())"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"request_content = {\n",
" 'mult_index': 0,\n",
" 'mult_by': 2.5,\n",
" 'array': [[1, 2, 3], [4, 5, 6], [7, 8, 9]],\n",
" 'api_token': 'thisshouldbeahashedstringwithhighentropy'\n",
"}\n",
"\n",
"resp = requests.get(\n",
" 'http://localhost:5000/scalar_multiplication',\n",
" json=request_content\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[2.5, 5. , 7.5],\n",
" [4. , 5. , 6. ],\n",
" [7. , 8. , 9. ]])"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"np.array(resp.json())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from functools import wraps
import numpy as np
from flask import Flask, request, Response, jsonify
from numerical_methods import row_interchange, scalar_multiplication, add_scalar_mult
app = Flask(__name__)

creds = {'example_user': 'example_password'}
acceptable_tokens = {'thisshouldbeahashedstringwithhighentropy', }


def check_http_basic_auth(username, password):
# Hopefully it goes without saying that we would never
# store these credentials in plain-text in the real world.
if username is None or password is None:
return False

return creds.get(username) == password


def http_login_required(f):
@wraps(f)
def required_login_wrapper(*args, **kwargs):
auth = request.authorization
if check_http_basic_auth(auth.username, auth.password):
return f(*args, **kwargs)
else:
return Response('Failed auth', 403)

return required_login_wrapper


def check_api_token(api_token):
return api_token in acceptable_tokens


def api_token_required(f):
@wraps(f)
def required_login_wrapper(*args, **kwargs):
if check_api_token(request.json['api_token']):
return f(*args, **kwargs)
else:
return Response('Failed token check', 403)
return required_login_wrapper


def make_array_from_json(js):
array_as_json = js.get('array')
try:
return np.array(array_as_json, dtype=np.float64)
except Exception: # Should be catching a more specific error
return Response('Could not create a NumPy array from request', 400)


@app.route('/row_interchange')
@http_login_required
def basic_auth_row_interchange():
req_content = request.json
np_array = make_array_from_json(req_content)
res = row_interchange(np_array, req_content['index_one'], req_content['index_two'])
return jsonify(res.tolist())


@app.route('/scalar_multiplication')
@api_token_required
def api_token_scalar_multiplication():
req_content = request.json
np_array = make_array_from_json(req_content)
res = scalar_multiplication(np_array, req_content['mult_index'], req_content['mult_by'])
return jsonify(res.tolist())


if __name__ == '__main__':
app.run(debug=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import numpy as np


def row_interchange(arr: np.ndarray, index_one: int, index_two: int):
res = arr.copy()
res[[index_one, index_two]] = res[[index_two, index_one]]
return res


def scalar_multiplication(
arr: np.ndarray,
mult_index: int,
multiply_by: np.float64
):
res = arr.copy()
res[mult_index] *= multiply_by
return res


def add_scalar_mult(
arr: np.ndarray,
mult_index: int,
multiply_by: np.float64,
add_index: int
):
res = arr.copy()
res[add_index] += res[mult_index] * multiply_by
return res
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import numpy as np
import pytest
from hypothesis import given
from hypothesis.strategies import integers, tuples, floats
from hypothesis.extra.numpy import arrays
from numerical_methods import row_interchange, scalar_multiplication, add_scalar_mult


# For the sake of simplicity, not bothering with nans or infs.
reasonable_floats = floats(min_value=0.001, max_value=10 * 7, allow_nan=False, allow_infinity=False)
reasonable_f_array = arrays(
dtype=np.float64,
shape=tuples(integers(min_value=2, max_value=250), integers(min_value=2, max_value=250)),
elements=reasonable_floats
)


@given(reasonable_f_array)
def test_row_interchange(arr):
num_rows = arr.shape[0]
index_one = np.random.randint(0, num_rows)
index_two = np.random.randint(0, num_rows)

res = row_interchange(arr, index_one, index_two)

# Confirm the arrays have been changed
np.testing.assert_array_equal(arr[index_one], res[index_two])
np.testing.assert_array_equal(res[index_one], arr[index_two])

# If we swap the rows back, arrays should be perfectly equal
res[[index_one, index_two]] = res[[index_two, index_one]]
np.testing.assert_array_equal(res, arr)


@given(reasonable_f_array, reasonable_floats)
def test_scalar_multiplication(arr, multiplier):
row_to_mult = np.random.randint(0, arr.shape[0])

res = scalar_multiplication(arr, row_to_mult, multiplier)

# We would expect that row_to_mult would be arr[row_to_mult] * multiplier
np.testing.assert_array_equal(arr[row_to_mult] * multiplier, res[row_to_mult])

# And if we scale it back down, we'd expect the arrays to be the same.
res[row_to_mult] /= multiplier
# almost_equal needed due to potential imprecision on the way back
np.testing.assert_array_almost_equal(arr, res)


@given(reasonable_f_array, reasonable_floats)
def test_add_scalar_mult(arr, multiplier):
row_to_mult = np.random.randint(0, arr.shape[0])
row_to_add = np.random.randint(0, arr.shape[0])

res = add_scalar_mult(arr, row_to_mult, multiplier, row_to_add)

# We would expect that row_to_add would be row_to_add + (row_to_mult * multiplier)
np.testing.assert_array_equal(arr[row_to_add] + (arr[row_to_mult] * multiplier), res[row_to_add])

# And if we scale it back down, we'd expect the arrays to be the same.
res[row_to_add] -= arr[row_to_mult] * multiplier
# almost_equal needed due to potential imprecision on the way back
np.testing.assert_array_almost_equal(arr, res)


if __name__ == '__main__':
pytest.main([__file__, '-s'])