diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..1854740e --- /dev/null +++ b/.flake8 @@ -0,0 +1,5 @@ +[flake8] +exclude = + venv +max-line-length = 88 +extend-ignore = E231 diff --git a/.github/workflows/pythonapp.yml b/.github/workflows/pythonapp.yml index 9f05b1cf..6c83f70b 100644 --- a/.github/workflows/pythonapp.yml +++ b/.github/workflows/pythonapp.yml @@ -15,13 +15,10 @@ jobs: steps: - uses: actions/checkout@v1 - - name: setup PYTHONPATH - run: | - export PYTHONPATH=${PWD}:${PYTHONPATH} - name: Lint with flake8 run: | # stop the build if flake8 fails. - flake8 . --count --show-source --statistics + flake8 . --extend-ignore=E231 --count --show-source --statistics # exit-zero treats all errors as warnings. flake8 . --count --exit-zero --max-complexity=10 --statistics - name: Test with python unittest diff --git a/README.md b/README.md index 2d85d201..d0b7a656 100644 --- a/README.md +++ b/README.md @@ -16,21 +16,15 @@ We can synthesize neural-network controllers with Lyapunov stability guarantees. ## Python requirements We use python 3 in this project. You could first install the packages in requirements.txt. -## Install gurobi -Please download gurobi from https://www.gurobi.com/products/gurobi-optimizer/. We require at least gurobi 9.5. After downloading the software, please install its Python API by following https://www.gurobi.com/documentation/9.0/quickstart_mac/the_grb_python_interface_f.html - -To check your gurobi installation, type the following command in your terminal: +## Installation +Please run ``` -$ python3 -c "import gurobipy" +pip install -e . ``` -There should be no error thrown when executing the command. +to install the package together with the dependencies. -## Setup environment variable -In the terminal, please run -``` -$ python3 setup.py -``` -It will print out the command to setup the environment variables. Execute that command in your terminal. +## Setup gurobi +Please refer to https://support.gurobi.com/hc/en-us/articles/360044290292-How-do-I-install-Gurobi-for-Python- on setting up Gurobi. Note that by default Gurobi ships with a limited license that has size limits on the optimization problem. Please refer to https://support.gurobi.com/hc/en-us/articles/360051597492 on using your own academic or commential license. ## Run a toy example You could run diff --git a/neural_network_lyapunov/examples/car/train_acceleration_car_demo.py b/neural_network_lyapunov/examples/car/train_acceleration_car_demo.py index 124ae218..4daab1f2 100644 --- a/neural_network_lyapunov/examples/car/train_acceleration_car_demo.py +++ b/neural_network_lyapunov/examples/car/train_acceleration_car_demo.py @@ -73,9 +73,10 @@ def compute_delta_pos(model, network_input): if __name__ == "__main__": - raise Exception("Dubins car cannot be stabilized by a continuous controller, refer" + - "to https://arxiv.org/pdf/math/9902026.pdf for a proof. Using" + - "neural-network controllers is doomed to fail for Dubins car.") + raise Exception("Dubins car cannot be stabilized by a continuous controller," + + "referto https://arxiv.org/pdf/math/9902026.pdf for a proof." + + "Using neural-network controllers is doomed to fail for Dubins" + + "car.") parser = argparse.ArgumentParser( description="Acceleration car training demo") parser.add_argument("--generate_dynamics_data", action="store_true") diff --git a/neural_network_lyapunov/examples/car/train_unicycle_demo.py b/neural_network_lyapunov/examples/car/train_unicycle_demo.py index f8196542..96815a26 100644 --- a/neural_network_lyapunov/examples/car/train_unicycle_demo.py +++ b/neural_network_lyapunov/examples/car/train_unicycle_demo.py @@ -153,9 +153,10 @@ def compute_v(model, x): if __name__ == "__main__": - raise Exception("Dubins car cannot be stabilized by a continuous controller, refer" + - "to https://arxiv.org/pdf/math/9902026.pdf for a proof. Using" + - "neural-network controllers is doomed to fail for Dubins car.") + raise Exception("Dubins car cannot be stabilized by a continuous controller," + + " refer to https://arxiv.org/pdf/math/9902026.pdf for a proof." + + " Using neural-network controllers is doomed to fail for Dubins" + + " car.") parser = argparse.ArgumentParser(description="Unicycle training demo") parser.add_argument("--generate_dynamics_data", action="store_true") parser.add_argument("--load_dynamics_data", diff --git a/neural_network_lyapunov/examples/quadrotor3d/visualize_quadrotor3d.py b/neural_network_lyapunov/examples/quadrotor3d/visualize_quadrotor3d.py index 42291117..e973c9b0 100644 --- a/neural_network_lyapunov/examples/quadrotor3d/visualize_quadrotor3d.py +++ b/neural_network_lyapunov/examples/quadrotor3d/visualize_quadrotor3d.py @@ -90,10 +90,10 @@ def get_mesh_markers(traj, num_markers): args = parser.parse_args() traj = np.load(args.file) - assert(isinstance(traj, np.ndarray)) - assert(len(traj.shape) == 2) - assert(traj.shape[0] >= 6) - assert(traj.shape[1] >= 2) + assert (isinstance(traj, np.ndarray)) + assert (len(traj.shape) == 2) + assert (traj.shape[0] >= 6) + assert (traj.shape[1] >= 2) mesh_pub = rospy.Publisher('animated_mesh', Marker, queue_size=10) traj_line_pub = rospy.Publisher('traj_line', Marker, queue_size=10) diff --git a/neural_network_lyapunov/examples/rl/td3.py b/neural_network_lyapunov/examples/rl/td3.py index a99816b8..7f51cf8a 100644 --- a/neural_network_lyapunov/examples/rl/td3.py +++ b/neural_network_lyapunov/examples/rl/td3.py @@ -323,7 +323,7 @@ def test_agent(epoch): mean_ret = 0. for j in range(num_test_episodes): o, d, ep_ret, ep_len = test_env.reset(), False, 0, 0 - while not(d or (ep_len == max_ep_len)): + while not (d or (ep_len == max_ep_len)): # Take deterministic actions at test time (noise_scale=0) o, r, d, _ = test_env.step(get_action(o, 0)) ep_ret += r diff --git a/neural_network_lyapunov/examples/tinydiffsim/learn_ca_dyn.py b/neural_network_lyapunov/examples/tinydiffsim/learn_ca_dyn.py index 03d7a95c..bbb923ee 100644 --- a/neural_network_lyapunov/examples/tinydiffsim/learn_ca_dyn.py +++ b/neural_network_lyapunov/examples/tinydiffsim/learn_ca_dyn.py @@ -65,7 +65,7 @@ def generate_dataset(cfg, mb, actuation_mask): j += 1 else: tau[i] = 0 - assert(j == u_dim) + assert (j == u_dim) mb.q = q mb.qd = qd diff --git a/neural_network_lyapunov/utils.py b/neural_network_lyapunov/utils.py index f1967052..da34766c 100644 --- a/neural_network_lyapunov/utils.py +++ b/neural_network_lyapunov/utils.py @@ -906,7 +906,6 @@ def leaky_relu_interval(negative_slope, x_lo, x_up): [output_lo, output_up] """ assert (x_up > x_lo) - assert (type(x_lo) == type(x_up)) if (negative_slope >= 0): if x_lo >= 0: if isinstance(x_lo, torch.Tensor): diff --git a/requirements.txt b/requirements.txt index 0c8aa698..e370ba22 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,10 @@ -pytorch >= 1.8 +cvxpy >= 1.1 +flake8 +gurobipy == 10.0 +matplotlib numpy >= 1.18 +pybullet +torch scipy >= 1.4 tensorboard >= 2.3 -pybullet -cvxpy >= 1.1 +wandb diff --git a/setup.py b/setup.py index 864c32f1..8a8c2b53 100644 --- a/setup.py +++ b/setup.py @@ -1,24 +1,12 @@ -import os - -from os.path import dirname, abspath, isdir - - -def main(): - cur_dir = dirname(abspath(__file__)) - # Now add this folder to PYTHONPATH - setup_script = cur_dir + "/config/setup_environments.sh" - if not isdir(cur_dir+"/config"): - print("create config folder") - os.mkdir(cur_dir+"/config") - with open(setup_script, "a") as f: - f.write(f""" - export PYTHONPATH={cur_dir}:${{PYTHONPATH}} - """) - print(""" - To use neural_network_lyapunov functionality: - source ./config/setup_environments.sh - """) - - -if __name__ == "__main__": - main() +from setuptools import setup, find_packages + +# Read the contents of requirements file +with open("requirements.txt") as f: + requirements = f.read().splitlines() + +setup( + name="neural-network-lyapunov", + version="0.1", + packages=find_packages(), + install_requires=requirements, +)