diff --git a/MaxCut.jl/LICENSE.md b/MaxCut.jl/LICENSE.md
new file mode 100644
index 0000000000000000000000000000000000000000..0fab6ae24acb4f128c5576ffb5a78fadaf81f303
--- /dev/null
+++ b/MaxCut.jl/LICENSE.md
@@ -0,0 +1,28 @@
+The MaxCut.jl package is licensed under the MIT "Expat" License:
+
+> Copyright (c) 2021: Eric Proffitt.
+>
+> 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.
+
+This software uses supporting software with their own licenses:
+
+https://github.com/JuliaLang/julia/blob/master/LICENSE.md<br />
+https://github.com/jump-dev/Convex.jl/blob/master/LICENSE.md<br />
+https://github.com/jump-dev/SCS.jl/blob/master/LICENSE.md
diff --git a/MaxCut.jl/Project.toml b/MaxCut.jl/Project.toml
new file mode 100644
index 0000000000000000000000000000000000000000..c08a1789f34eb3b14c110fb76c9f1a3091812af1
--- /dev/null
+++ b/MaxCut.jl/Project.toml
@@ -0,0 +1,12 @@
+name = "MaxCut"
+uuid = "6af15267-3226-46fb-9d72-8bee1ad40623"
+version = "1.0.1"
+
+[deps]
+LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
+Convex = "f65535da-76fb-5f13-bab9-19810c17039a"
+SCS = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13"
+
+[compat]
+julia = "1"
+Convex = "~0.14.16"
diff --git a/MaxCut.jl/README.md b/MaxCut.jl/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..563bfc3a281b1eecf9e167879b357f2266e3833d
--- /dev/null
+++ b/MaxCut.jl/README.md
@@ -0,0 +1,46 @@
+**The Goemans-Williamson algorithm for the MAXCUT problem.**
+
+Partition a graph into two disjoint sets such that the sum of the edge weights which cross the partition is as large as possible (known to be NP-hard).
+
+A cut of a graph can be produced by assigning either 1 or -1 to each vertex. The Goemans-Williamson algorithm relaxes this binary constraint to allow for vector assignments drawn from the (n-1)-sphere (choosing an n-1 dimensional space will ensure seperability). This relaxation can then be written as a semidefinite program. Once the optimal vector assignments are found, origin centered hyperplanes are generated and their corresponding cuts evaluated. After `iter` trials, or when the desired tolerance is reached, the hyperplane with the highest corresponding binary cut is used to partition the vertices.
+
+### Installation
+```julia
+(@v1.7) pkg> add https://github.com/ericproffitt/MaxCut.jl
+```
+
+### Dependencies
+```julia
+LinearAlgebra
+Convex
+SCS
+```
+
+### Arguments
+```julia
+W:      Adjacency matrix.
+tol:    (keyword arg) Maximum acceptable distance between a cut and the MAXCUT upper bound (default=0).
+iter:   (keyword arg) Maximum number of hyperplane iterations before a cut is chosen (default=100).
+```
+
+### Example
+```julia
+using MaxCut
+
+W = [0 5 2 1 0; 
+     5 0 3 2 0; 
+     2 3 0 0 0; 
+     1 2 0 0 4; 
+     0 0 0 4 0];
+
+max_cut, max_partition = maxcut(W);
+	
+@show max_cut;
+## max_cut = 14
+
+@show max_partition;
+## max_partition = ([1, 3, 4], [2, 5])
+```
+
+### Reference
+http://www.sfu.ca/~mdevos/notes/semidef/GW.pdf
\ No newline at end of file
diff --git a/MaxCut.jl/src/MaxCut.jl b/MaxCut.jl/src/MaxCut.jl
new file mode 100644
index 0000000000000000000000000000000000000000..4cd806f1a6430ac3d7de1320855fa23a665f6681
--- /dev/null
+++ b/MaxCut.jl/src/MaxCut.jl
@@ -0,0 +1,71 @@
+module MaxCut
+
+using LinearAlgebra
+using Convex
+using SCS
+
+"The Goemans-Williamson algorithm for the MAXCUT problem."
+
+function maxcut(W::Matrix{<:Real}; iter::Int=100, tol::Real=0)
+	"Partition a graph into two disjoint sets such that the sum of the edge weights
+	which cross the partition is as large as possible (known to be NP-hard)."
+
+	"A cut of a graph can be produced by assigning either 1 or -1 to each vertex. The Goemans-Williamson 
+	algorithm relaxes this binary condition to allow for vector assignments drawn from the (n-1)-sphere
+	(choosing an n-1 dimensional space will ensure seperability). This relaxation can then be written as 
+	a semidefinite program. Once the optimal vector assignments are found, origin centered hyperplanes are generated and 
+	their corresponding cuts evaluated. After 'iter' trials, or when the desired tolerance is reached,
+	the hyperplane with the highest corresponding binary cut is used to partition the vertices."
+	
+	"W:		Adjacency matrix."
+	"tol:	Maximum acceptable distance between a cut and the MAXCUT upper bound."
+	"iter:	Maximum number of hyperplane iterations before a cut is chosen."
+
+	LinearAlgebra.checksquare(W)
+	issymmetric(W)					|| throw(ArgumentError("Adjacency matrix must be symmetric."))
+	all(W .>= 0)					|| throw(ArgumentError("Adjacency matrix must be nonnegative."))
+	all(iszero.(diag(W)))			|| throw(ArgumentError("Diagonal of adjacency matrix must be zero (no self loops)."))
+	(tol >= 0)						|| throw(ArgumentError("The tolerance must be nonnegative."))
+	(iter > 0)						|| throw(ArgumentError("The number of iterations must be a positive integer."))
+
+	"This is the standard SDP Relaxation of the MAXCUT problem, a reference can be found at,
+	http://www.sfu.ca/~mdevos/notes/semidef/GW.pdf"
+	k = size(W, 1)
+	S = Semidefinite(k)
+	
+	expr = dot(W, S)
+	constr = [S[i,i] == 1.0 for i in 1:k]
+	problem = minimize(expr, constr...)
+	solve!(problem, SCS.Optimizer; silent_solver=true)
+
+	## ensure symmetric positive-definite
+	A = 0.5 * (S.value + S.value')
+	A += (max(0, -eigmin(A)) + 1e-14) * Matrix(I, size(A, 1), size(A, 1))
+
+	X = Matrix(cholesky(A))
+
+	## a non-trivial upper bound on MAXCUT
+	upperbound = (sum(W) - dot(W, S.value)) / 4
+
+	## random origin-centered hyperplanes, generated to produce partitions of the graph
+	max_cut = -1
+	max_partition = nothing
+
+	for i in 1:iter
+		gweval = X' * randn(k)
+		partition = (findall(gweval .>= 0), findall(gweval .< 0))
+		cut = sum(W[partition...])
+
+		if cut > max_cut
+			max_partition = partition
+			max_cut = cut
+		end
+
+		(upperbound - max_cut < tol) && break
+	end
+	return max_cut, max_partition
+end
+
+export maxcut
+
+end
diff --git a/algo/maxcut.cpp b/algo/maxcut.cpp
index 1983bb3bb64e9babbf7c22b68253e9c116d849a3..09e3854ebab089b2533ab96a787495233c437938 100644
--- a/algo/maxcut.cpp
+++ b/algo/maxcut.cpp
@@ -1,10 +1,11 @@
 #include "../main.h"
 #include <stdlib.h>
 #include <assert.h>
+#include <cstring>
 
 using std::pair;
 
-const int VERSION = 5;
+const int VERSION = 1;
 const bool ALLOW_MISTAKES = 1;
 
 struct Nd {
@@ -13,7 +14,7 @@ struct Nd {
 };
 
 
-void calc_maxcut(Nd * nd, int nd_size)
+void calc_maxcut_naive(Nd * nd, int nd_size)
 {
 	fo(i, nd_size) nd[i].color = false;
 	bool change = true;
@@ -39,11 +40,65 @@ void calc_maxcut(Nd * nd, int nd_size)
 	}
 }
 
+void calc_maxcut_gw(Nd * nd, int nd_size)
+{
+	auto [p_stdin, p_stdout] = lib::dualpopen("julia");
+	{
+		vector<vector<int>> matrix(nd_size, vector<int>(nd_size, 0));
+		fo(i, nd_size)
+			for(auto [target, weight] : nd[i].edges)
+				matrix[i][target-nd] += weight;
+
+		fprintf(p_stdin,
+				"include(\"MaxCut.jl/src/MaxCut.jl\");\
+				using Random;\
+				Random.seed!(3);\
+				MaxCut.maxcut([");
+		fo(i,nd_size)
+		{
+			fo(j, nd_size) fprintf(p_stdin, " %d", matrix[i][j]);
+			fprintf(p_stdin, ";");
+			//fo(j, nd_size) fprintf(stderr, " %d", matrix[i][j]);
+			//fprintf(stderr, ";\n");
+		}
+		fprintf(p_stdin, "])[2][1]\n");
+	}
+	fflush(p_stdin);
+
+	char * line;
+	int elements;
+	assert(fscanf(p_stdout, "%d%m[^\n]", &elements, &line)==2);
+	assert(!strcmp(line, "-element Vector{Int64}:"));
+	delete [] line;
+
+	fo(i, nd_size) nd[i].color = false;
+	fo(i, elements)
+	{
+		int val;
+		assert(fscanf(p_stdout, "%d", &val)==1);
+		val--;
+		//fprintf(stderr, "-> %d\n", val);
+		nd[val].color = true;
+	}
+	fclose(p_stdin);
+	fclose(p_stdout);
+}
+
+void calc_maxcut(Nd * nd, int nd_size, const char * algorithm)
+{
+	if(!strcmp("naive", algorithm)) calc_maxcut_naive(nd, nd_size);
+	else
+	if(!strcmp("gw", algorithm)) calc_maxcut_gw(nd, nd_size);
+	else assert(false);
+}
+
 vector<bool> solve(int n, vector<int> input,
 		int argc, char const* const* argv)
 {
-	int cars_per_vertex = argc>=1?atoi(argv[0]):3;
+	assert(argc==2);
+	int cars_per_vertex = atoi(argv[0]);
 	assert(cars_per_vertex>0);
+	const char * maxcut_algorithm = argv[1];
 	vector<int> other = lib::gen_arr_other_car_of_type(n, input);
 	vector<bool> out(2*n);
 	int nd_size = (2*n -1)/cars_per_vertex + 1;
@@ -57,7 +112,7 @@ vector<bool> solve(int n, vector<int> input,
 			nd[a].edges.push_back({nd + b, 1});
 	}
 
-	calc_maxcut(nd, nd_size);
+	calc_maxcut(nd, nd_size, maxcut_algorithm);
 
 	fo(i, 2*n)
 		out[i] = nd[i/cars_per_vertex].color;