Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: derohde/Fred
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.5
Choose a base ref
...
head repository: derohde/Fred
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref

Commits on Aug 14, 2021

  1. Update CMakeLists

    derohde committed Aug 14, 2021
    Copy the full SHA
    e70b773 View commit details

Commits on Aug 16, 2021

  1. Switch to PyBind11

    derohde committed Aug 16, 2021
    Copy the full SHA
    a464444 View commit details
  2. PyPI

    derohde committed Aug 16, 2021
    Copy the full SHA
    2c7089d View commit details

Commits on Aug 20, 2021

  1. Fixes in Clustering

    derohde committed Aug 20, 2021
    Copy the full SHA
    1103cc2 View commit details

Commits on Aug 23, 2021

  1. bugfix and small changes

    derohde committed Aug 23, 2021
    Copy the full SHA
    74c8d4d View commit details

Commits on Aug 24, 2021

  1. Copy the full SHA
    fb8c547 View commit details
  2. coreset

    derohde committed Aug 24, 2021
    Copy the full SHA
    bf6cff6 View commit details

Commits on Aug 27, 2021

  1. OpenMP and Tidy Up

    derohde committed Aug 27, 2021
    Copy the full SHA
    53d761e View commit details

Commits on Aug 29, 2021

  1. Copy the full SHA
    2b27833 View commit details

Commits on Aug 30, 2021

  1. Copy the full SHA
    40e3e8d View commit details

Commits on Sep 3, 2021

  1. improve clustering framework

    derohde committed Sep 3, 2021
    Copy the full SHA
    9493a83 View commit details
  2. important numeric fixes

    derohde committed Sep 3, 2021
    Copy the full SHA
    e01d30b View commit details
  3. verbosity

    derohde committed Sep 3, 2021
    Copy the full SHA
    aeb9fb9 View commit details

Commits on Sep 7, 2021

  1. clock and tests

    derohde committed Sep 7, 2021
    Copy the full SHA
    507ebaa View commit details

Commits on Sep 10, 2021

  1. switch to cpu clock

    derohde committed Sep 10, 2021
    Copy the full SHA
    b8f784e View commit details

Commits on Sep 15, 2021

  1. median coreset & verbosity

    derohde committed Sep 15, 2021
    Copy the full SHA
    a7d0e2a View commit details

Commits on Sep 16, 2021

  1. code quality

    derohde committed Sep 16, 2021
    Copy the full SHA
    368e191 View commit details

Commits on Nov 17, 2021

  1. randomized dtw algorithm

    derohde committed Nov 17, 2021
    Copy the full SHA
    9021bd0 View commit details

Commits on Nov 21, 2021

  1. Copy the full SHA
    98b8f5a View commit details

Commits on Apr 29, 2022

  1. Copy the full SHA
    8bf2296 View commit details

Commits on May 7, 2022

  1. plot function

    derohde committed May 7, 2022
    Copy the full SHA
    c28d39e View commit details

Commits on May 16, 2022

  1. Copy the full SHA
    252b450 View commit details

Commits on Jun 9, 2022

  1. plot functions

    derohde committed Jun 9, 2022
    Copy the full SHA
    402e045 View commit details

Commits on Nov 30, 2022

  1. Build for windows

    Dennis Rohde committed Nov 30, 2022
    Copy the full SHA
    c449b75 View commit details

Commits on Dec 1, 2022

  1. installation for different oses

    Dennis Rohde committed Dec 1, 2022
    Copy the full SHA
    5294c27 View commit details

Commits on Dec 9, 2022

  1. make library work with apple

    Dennis Rohde committed Dec 9, 2022
    Copy the full SHA
    9737ff1 View commit details

Commits on Jan 17, 2023

  1. revision; preparing for center optimization

    Dennis Rohde committed Jan 17, 2023
    Copy the full SHA
    ca02e27 View commit details

Commits on Jan 18, 2023

  1. optimize_centers prototype

    Dennis Rohde committed Jan 18, 2023
    Copy the full SHA
    56f2538 View commit details

Commits on Jan 23, 2023

  1. optimized centers

    Dennis Rohde committed Jan 23, 2023
    Copy the full SHA
    b4c1a1a View commit details

Commits on Jan 25, 2023

  1. fixes

    Dennis Rohde committed Jan 25, 2023
    Copy the full SHA
    284ad82 View commit details
  2. improve stabbing algorithm

    Dennis Rohde committed Jan 25, 2023
    Copy the full SHA
    4dbfaa6 View commit details

Commits on Jan 26, 2023

  1. bugfix

    Dennis Rohde committed Jan 26, 2023
    Copy the full SHA
    71d916e View commit details
  2. fix in approximate simplification

    Dennis Rohde committed Jan 26, 2023
    Copy the full SHA
    c7151a7 View commit details
  3. bugfix 2 approximate simplification

    Dennis Rohde committed Jan 26, 2023
    Copy the full SHA
    917a012 View commit details
  4. optimized center naming, update pybind

    Dennis Rohde committed Jan 26, 2023
    Copy the full SHA
    29fd6f0 View commit details
  5. update readme

    Dennis Rohde committed Jan 26, 2023
    Copy the full SHA
    69bc6f9 View commit details
  6. readme, plotting

    Dennis Rohde committed Jan 26, 2023
    Copy the full SHA
    cf325f6 View commit details
  7. plot fix

    Dennis Rohde committed Jan 26, 2023
    Copy the full SHA
    c723e61 View commit details

Commits on Jan 30, 2023

  1. code improvements, clustering improvements

    Dennis Rohde committed Jan 30, 2023
    Copy the full SHA
    3da00c9 View commit details

Commits on May 8, 2023

  1. Copy the full SHA
    375784d View commit details

Commits on May 9, 2023

  1. minor fixes

    Dennis Rohde committed May 9, 2023
    Copy the full SHA
    e3b5956 View commit details

Commits on Jul 10, 2023

  1. choose distance in clustering

    Dennis Rohde committed Jul 10, 2023
    Copy the full SHA
    3d52413 View commit details

Commits on Jul 12, 2023

  1. memory management

    Dennis Rohde committed Jul 12, 2023
    Copy the full SHA
    ce975a0 View commit details
  2. bugfix

    Dennis Rohde committed Jul 12, 2023
    Copy the full SHA
    2c6799b View commit details

Commits on Jul 15, 2023

  1. reveal cluster distances to python

    Dennis Rohde committed Jul 15, 2023
    Copy the full SHA
    3ffe6d6 View commit details

Commits on Jul 17, 2023

  1. make curve and curves pickleable

    Dennis Rohde committed Jul 17, 2023
    Copy the full SHA
    c5cafc4 View commit details

Commits on Aug 3, 2023

  1. DTW DBA

    Dennis Rohde committed Aug 3, 2023
    Copy the full SHA
    6ce4cab View commit details

Commits on Aug 7, 2023

  1. DTW contingency; fixes

    Dennis Rohde committed Aug 7, 2023
    Copy the full SHA
    b722ae4 View commit details

Commits on Aug 14, 2023

  1. Major fixes

    Dennis Rohde committed Aug 14, 2023
    Copy the full SHA
    75574da View commit details

Commits on Aug 15, 2023

  1. Minor fixes

    Dennis Rohde committed Aug 15, 2023
    Copy the full SHA
    40268d8 View commit details
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "pybind11"]
path = pybind11
url = https://github.com/pybind/pybind11.git
46 changes: 19 additions & 27 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,52 +1,44 @@
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
cmake_minimum_required(VERSION 3.16)
project(Fred LANGUAGES CXX C)

set( CMAKE_CXX_STANDARD 14 )

if(NOT APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Ofast")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -shared")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
if(NOT APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") #supress error in older gcc
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-trapping-math")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftree-vectorize")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopt-info-vec")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopt-info-loop")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--no-undefined")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -dynamic-linker")

include_directories(${CMAKE_SOURCE_DIR}/include)

find_package(PythonInterp REQUIRED)
find_package(PythonLibs REQUIRED)
find_package(Boost 1.63 COMPONENTS system chrono ${BPY} ${BNPY} REQUIRED)
find_package(OpenMP REQUIRED)

add_definitions(-D_GLIBCXX_PARALLEL)

include_directories(${PYTHON_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
link_libraries(${PYTHON_LIBRARIES} ${Boost_LIBRARIES})

find_package(OpenMP)
if(OpenMP_CXX_FOUND)
link_libraries(OpenMP::OpenMP_CXX)
add_compile_definitions(WITH_OMP)
else()
message(WARNING "Compiling without openmp")
endif()
if(NOT TARGET OpenMP::OpenMP_CXX)
find_package(Threads REQUIRED)
add_library(OpenMP::OpenMP_CXX IMPORTED INTERFACE)
set_property(TARGET OpenMP::OpenMP_CXX
PROPERTY INTERFACE_COMPILE_OPTIONS ${OpenMP_CXX_FLAGS})
set_property(TARGET OpenMP::OpenMP_CXX
PROPERTY INTERFACE_LINK_LIBRARIES ${OpenMP_CXX_FLAGS} Threads::Threads)

endif()
link_libraries(OpenMP::OpenMP_CXX)
add_subdirectory(pybind11)

PYTHON_ADD_MODULE(backend
src/fred_python_wrapper.cpp
pybind11_add_module(backend
src/curve.cpp
src/point.cpp
src/interval.cpp
src/frechet.cpp
src/jl_transform.cpp
src/simplification.cpp
src/dynamic_time_warping.cpp
src/clustering.cpp
src/config.cpp
src/bounding.cpp
src/fred_python_wrapper.cpp
)
169 changes: 169 additions & 0 deletions Fred/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
"""
Copyright 2020 - 2023 Dennis Rohde
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from .backend import Curve, Curves, continuous_frechet, discrete_dynamic_time_warping, discrete_frechet, discrete_klcenter, discrete_klmedian, dimension_reduction, dtw_approximate_minimum_error_simplification, frechet_approximate_minimum_error_simplification, frechet_approximate_minimum_link_simplification, frechet_minimum_error_simplification
from .stabbing import stabbing_path as _stabbing_path

import psutil
import numpy as np

config = backend.Config()
config.available_memory = psutil.virtual_memory().available

def _optimize_centers(self, curves, consecutive_call=False):
all_balls = self.compute_center_enclosing_balls(curves, consecutive_call)
for i, center_balls in enumerate(all_balls):
if self.distance_func == 0:
path, _ = _stabbing_path(center_balls)
else:
path = np.array([b[0] for b in center_balls])
self[i] = Curve(path, "{} (optimized)".format(self[i].name))

backend.Clustering_Result.optimize_centers = _optimize_centers

def plot_curve(*curves, vertex_markings=True, savename=None, saveextension=None, return_fig=False, legend=True):
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
max_compl = 1
max_dim = 1
fig = plt.figure()
ax = None
for curve in curves:
if isinstance(curve, backend.Curve):
max_compl = max(max_compl, curve.complexity)
max_dim = max(max_dim, curve.dimensions)
elif isinstance(curve, backend.Curves):
for curv in curve:
max_compl = max(max_compl, curv.complexity)
max_dim = max(max_dim, curv.dimensions)
elif isinstance(curve, backend.Clustering_Result):
for curv in curve:
max_compl = max(max_compl, curv.complexity)
max_dim = max(max_dim, curv.dimensions)
if max_dim >= 3:
ax = fig.add_subplot(projection='3d')
else:
ax = fig.gca()
for curve in curves:
if isinstance(curve, backend.Curve):
if curve.dimensions >= 3:
p = ax.plot(curve.values[:, 0], curve.values[:, 1], curve.values[:, 2], linestyle='--', marker='o', label = curve.name, markersize = 7, markevery = curve.complexity)
if vertex_markings:
ax.plot(curve.values[1:, 0], curve.values[1:, 1], curve.values[1:, 2], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
elif curve.dimensions == 2:
p = ax.plot(curve.values[:, 0], curve.values[:, 1], linestyle='--', marker='o', label = curve.name, markersize = 7, markevery = curve.complexity)
if vertex_markings:
ax.plot(curve.values[1:, 0], curve.values[1:, 1], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
else:
p = ax.plot([i * max_compl / len(curve) for i in range(len(curve))], curve.values, linestyle='--', marker='o', label = curve.name, markersize = 7, markevery = curve.complexity)
if vertex_markings:
ax.plot([i * max_compl / len(curve) for i in range(1, len(curve))], curve.values[1:], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
elif isinstance(curve, backend.Curves):
for curv in curve:
if curv.dimensions >= 3:
p = ax.plot(curv.values[:, 0], curv.values[:, 1], curv.values[:, 2], linestyle='--', marker='o', label = curv.name, markersize = 7, markevery = curv.complexity)
if vertex_markings:
ax.plot(curv.values[1:, 0], curv.values[1:, 1], curv.values[1:, 2], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
elif curv.dimensions == 2:
p = plt.plot(curv.values[:, 0], curv.values[:, 1], linestyle='--', marker='o', label = curv.name, markersize = 7, markevery = curv.complexity)
if vertex_markings:
plt.plot(curv.values[1:, 0], curv.values[1:, 1], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
else:
p = plt.plot([i * max_compl / len(curv) for i in range(len(curv))], curv.values, linestyle='--', marker='o', label = curv.name, markersize = 7, markevery = curv.complexity)
if vertex_markings:
plt.plot([i * max_compl / len(curv) for i in range(1, len(curv))], curv.values[1:], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
elif isinstance(curve, backend.Clustering_Result):
for curv in curve:
if curv.dimensions >= 3:
p = ax.plot(curv.values[:, 0], curv.values[:, 1], curv.values[:, 2], linestyle='-', marker='o', label = curv.name, markersize = 7, markevery = curv.complexity)
if vertex_markings:
ax.plot(curv.values[1:, 0], curv.values[1:, 1], curv.values[1:, 2], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
elif curv.dimensions == 2:
p = plt.plot(curv.values[:, 0], curv.values[:, 1], linestyle='-', marker='o', label = curv.name, markersize = 7, markevery = curv.complexity)
if vertex_markings:
plt.plot(curv.values[1:, 0], curv.values[1:, 1], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
else:
p = plt.plot([i * max_compl / len(curv) for i in range(len(curv))], curv.values, linestyle='-', marker='o', label = curv.name, markersize = 7, markevery = curv.complexity)
if vertex_markings:
plt.plot([i * max_compl / len(curv) for i in range(1, len(curv))], curv.values[1:], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
if legend:
ax.legend(title='Curve names:')
ax.set_title('Fred Curves')
if savename is not None:
plt.savefig("{}.{}".format(savename, saveextension), dpi=150)
plt.close()
elif return_fig:
return fig
else:
plt.show(block=False)

def plot_clustering(clustering_result, curves, vertex_markings=True, savename=None, saveextension=None, return_fig=False, legend=True):
if not (isinstance(clustering_result, backend.Clustering_Result) and isinstance(curves, backend.Curves)):
print("Check parameters!")
return
if clustering_result.assignment is None:
print("compute_assignment was not called! calling now")
clustering_result.compute_assignment(curves)
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
colors = list(mcolors.BASE_COLORS)
if len(clustering_result) > len(colors):
colors = list(mcolors.TABLEAU_COLORS)
if len(clustering_result) > len(colors):
colors = list(mcolors.mcolors.CSS4_COLORS)
max_compl = 1
max_dim = 1
fig = plt.figure()
ax = None
for curve in curves:
max_compl = max(max_compl, curve.complexity)
max_dim = max(max_dim, curve.dimensions)
if max_dim >= 3:
ax = fig.add_subplot(projection='3d')
else:
ax = fig.gca()
for i, curve in enumerate(clustering_result):
if curve.dimensions >= 3:
p = ax.plot(curve.values[:, 0], curve.values[:, 1], curve.values[:, 2], linestyle='-', marker='o', label = curve.name, color = colors[i], markersize = 7, markevery = curve.complexity)
if vertex_markings:
ax.plot(curve.values[1:, 0], curve.values[1:, 1], curve.values[1:, 2], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
elif curve.dimensions == 2:
p = ax.plot(curve.values[:, 0], curve.values[:, 1], linestyle='-', marker='o', label = curve.name, color = colors[i], markersize = 7, markevery = curve.complexity)
if vertex_markings:
ax.plot(curve.values[1:, 0], curve.values[1:, 1], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
else:
p = ax.plot([i * max_compl / len(curve) for i in range(len(curve))], curve.values, linestyle='-', marker='o', label = curve.name, color = colors[i], markersize = 7, markevery = curve.complexity)
if vertex_markings:
ax.plot([i * max_compl / len(curve) for i in range(1, len(curve))], curve.values[1:], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
for i in range(len(clustering_result.assignment)):
for j in range(clustering_result.assignment.count(i)):
curve = curves[clustering_result.assignment.get(i,j)]
if curve.dimensions >= 3:
p = ax.plot(curve.values[:, 0], curve.values[:, 1], curve.values[:, 2], linestyle=':', marker='o', label = curve.name, color = colors[i], markersize = 7, markevery = curve.complexity)
if vertex_markings:
ax.plot(curve.values[1:, 0], curve.values[1:, 1], curve.values[1:, 2], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
elif curve.dimensions == 2:
p = ax.plot(curve.values[:, 0], curve.values[:, 1], linestyle=':', marker='o', label = curve.name, color = colors[i], markersize = 7, markevery = curve.complexity)
if vertex_markings:
ax.plot(curve.values[1:, 0], curve.values[1:, 1], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
else:
p = ax.plot([i * max_compl / len(curve) for i in range(len(curve))], curve.values, linestyle=':', marker='o', label = curve.name, color = colors[i], markersize = 7, markevery = curve.complexity)
if vertex_markings:
ax.plot([i * max_compl / len(curve) for i in range(1, len(curve))], curve.values[1:], linestyle='', marker='x', label = None, color = p[0].get_color(), markersize = 7)
if legend:
ax.legend(title='Curve names:')
ax.set_title('Fred Clustering')
if savename is not None:
plt.savefig("{}.{}".format(savename, saveextension), dpi=150)
plt.close()
elif return_fig:
return fig
else:
plt.show(block=False)
9 changes: 9 additions & 0 deletions py/Fred/hd_fs.py → Fred/hd_fs.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
"""
Copyright 2020 - 2023 Dennis Rohde
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from . import backend

from cvxopt import matrix, solvers
9 changes: 9 additions & 0 deletions py/Fred/median.py → Fred/median.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
"""
Copyright 2020 Dennis Rohde
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
from . import backend
from .hd_fs import curve_within_radii

Loading