diff --git a/CovidAlertVaccinationModel/src/ABM/abm.jl b/CovidAlertVaccinationModel/src/ABM/abm.jl
index 4fc434d4685a8a5484be2200df50d5be3b75be45..f63f50b8d1f0a724b6bf9b5607c6d5b5eaf0bc0a 100644
--- a/CovidAlertVaccinationModel/src/ABM/abm.jl
+++ b/CovidAlertVaccinationModel/src/ABM/abm.jl
@@ -12,8 +12,7 @@ function bench()
     steps = 500
     model_sol = ModelSolution(steps,get_parameters(),5000)
     recording = DebugRecorder(steps)
-    solve!(model_sol,recording )
-    display(output.recorded_status_totals[2,:])
+    output = solve!(model_sol,recording )
 end
 
 function abm()
diff --git a/CovidAlertVaccinationModel/src/ABM/mixing_graphs.jl b/CovidAlertVaccinationModel/src/ABM/mixing_graphs.jl
index 1414a36d5e00fc958f1829988e6cefd48d8bee1c..7a113d106c8a03a31d4e04e7594d35e1fa3f1034 100644
--- a/CovidAlertVaccinationModel/src/ABM/mixing_graphs.jl
+++ b/CovidAlertVaccinationModel/src/ABM/mixing_graphs.jl
@@ -1,17 +1,39 @@
-#A type that defines a matrix of vectors, such that the sum of the ijth vector is equal to the sum of the jith vector
-struct MixingEdges{V}
+#A type that defines a matrix of vectors, such that the ijth vector contains the nodes to connect to the jith vector, ala. Chung-Lu bipartite
+struct MixingEdges
     total_edges::Int
-    contact_array::V
+    contact_array::Matrix{Tuple{Vector{Int},Vector{Int}}}
     function MixingEdges(demographic_index_vectors,mixing_matrix)
-        contacts = map(CartesianIndices(mixing_matrix)) do ind
-            zeros(Int,length(demographic_index_vectors[ind[1]]))
-        end
+        contact_array =[(Vector{Int}(),Vector{Int}()) for i in 1:length(demographic_index_vectors),j in 1:length(demographic_index_vectors)]
         tot = 0
-        for i in 1:length(mixing_matrix[:,1]), j in 1:i  #diagonal
-            generate_contact_vectors!(mixing_matrix[i,j],mixing_matrix[j,i],contacts[i,j],contacts[j,i] )
-            tot += sum(contacts[i,j])
+        for i in 1:size(mixing_matrix)[1], j in 1:i  #diagonal
+            num_degrees_ij = zeros(Int,length(demographic_index_vectors[i]))
+            num_degrees_ji = zeros(Int,length(demographic_index_vectors[j]))
+            generate_contact_vectors!(mixing_matrix[i,j],mixing_matrix[j,i],num_degrees_ij,num_degrees_ji)
+
+            m = sum(num_degrees_ij)
+            stubs_i = Vector{Int}(undef,m)
+            stubs_j = Vector{Int}(undef,m)
+            if m>0
+                # @assert m == sum(num_degrees_ji)
+                rand!(RNG,DiscreteNonParametric(demographic_index_vectors[i],num_degrees_ij./m),stubs_i)
+                rand!(RNG,DiscreteNonParametric(demographic_index_vectors[j],num_degrees_ji./m),stubs_j)
+                tot += m
+            end    
+            contact_array[j,i] = (stubs_i,stubs_j)
         end
-        new{typeof(contacts)}(tot,contacts)
+
+        new(tot,contact_array)
+    end
+    function MixingEdges(g::SimpleGraph,demographics,demographic_index_vectors)
+        contact_array = [(Vector{Int}(),Vector{Int}()) for i in 1:length(demographic_index_vectors),j in 1:length(demographic_index_vectors)]
+        for e in edges(g)    
+            i = src(e)
+            j = dst(e)
+            push!(contact_array[Int(demographics[j]),Int(demographics[i])][1],i)
+            push!(contact_array[Int(demographics[j]),Int(demographics[i])][2],j)
+        end 
+        # @show ne(g)
+        new(ne(g),contact_array)
     end
 end
 
@@ -25,38 +47,9 @@ struct TimeDepMixingGraph{N,G}
         )
     end
 end
-#modify g so that nodes specified in anodes and bnodes are connected by a bipartite graph with expected degrees given by aseq and bseq
-#implemented from Aksoy, S. G., Kolda, T. G., & Pinar, A. (2017). Measuring and modeling bipartite graphs with community structure
-#simple algorithm, lightgraphs does not allow parallel edges.
-#(also not actually that fast, this is a major bottleneck)
-function random_bipartite_graphs_fast!(g, demographic_index_vectors,mixing_contacts)
-    astubs = Vector{Int}(undef,mixing_contacts.total_edges)
-    bstubs = Vector{Int}(undef,mixing_contacts.total_edges)
-    stubs_ptr = 1
-    for i in 1:length(demographic_index_vectors), j in 1:i  #diagonal
-        anodes = demographic_index_vectors[i]
-        bnodes = demographic_index_vectors[j]
-        aseq = mixing_contacts.contact_array[i,j]
-        bseq = mixing_contacts.contact_array[j,i]
-        # @show sum(contacts[i,j])
-        m = Int(sum(aseq))
-        if m>0
-            astubs_ij = @view astubs[stubs_ptr:stubs_ptr + m - 1]  
-            bstubs_ij = @view bstubs[stubs_ptr:stubs_ptr + m - 1]  
-            @assert sum(aseq) == sum(bseq) "degree sequences must have equal sum"
-            rand!(RNG,DiscreteNonParametric(anodes,aseq./m),astubs_ij)
-            rand!(RNG,DiscreteNonParametric(bnodes,bseq./m),bstubs_ij)
-            for k in 1:m
-                add_edge!(g,astubs_ij[k], bstubs_ij[k])
-            end
-            stubs_ptr += m 
-        end
-    end
-    return astubs,bstubs
-end
 
 function time_dep_mixing_graphs(len,base_network,demographics,index_vectors,ws_matrix_tuple,rest_matrix_tuple)
-    home_static_edges = WeightedGraph(base_network,contact_time_distributions.hh) #network with households and LTC homes
+    home_static_edges = WeightedGraph(base_network,demographics,index_vectors,contact_time_distributions.hh) #network with households and LTC homes
     ws_static_edges = WeightedGraph(demographics,index_vectors,ws_matrix_tuple.daily,contact_time_distributions.ws)
     ws_weekly_edges = WeightedGraph(demographics,index_vectors,ws_matrix_tuple.twice_a_week,contact_time_distributions.ws)
     ws_daily_edges = WeightedGraph(demographics,index_vectors,ws_matrix_tuple.otherwise,contact_time_distributions.ws)
@@ -90,63 +83,76 @@ function remake!(time_dep_mixing_graph,demographic_index_vectors,mixing_matrix)
         empty!.(weighted_graph.g.fadjlist) #empty all the vector edgelists
         empty!(weighted_graph.weights_dict)
         weighted_graph.g.ne = 0
-        contacts = MixingEdges(demographic_index_vectors,mixing_matrix)
-        astubs,bstubs = random_bipartite_graphs_fast!(weighted_graph.g,demographic_index_vectors,contacts)
-        weighted_graph.astubs = astubs
-        weighted_graph.bstubs = bstubs
+        weighted_graph.mixing_edges = MixingEdges(demographic_index_vectors,mixing_matrix)
+        graph_from_mixing_edges(weighted_graph.g,weighted_graph.mixing_edges)
+        weighted_graph.sample_cache = map(v-> Vector{Int}(undef,length(v[1])),weighted_graph.mixing_edges.contact_array)
+    end
+end
+
+function graph_from_mixing_edges(g,mixing_edges)
+    for i in 1:size(mixing_edges.contact_array)[1], j in 1:i  #diagonal
+        for k in 1:length(mixing_edges.contact_array[i,j][1])
+            add_edge!(g,mixing_edges.contact_array[i,j][1][k],mixing_edges.contact_array[i,j][2][k])
+        end
     end
 end
+
 #defining my own weighted graph type cause we need to be able to resample the edge weights in a very particular way
 mutable struct WeightedGraph{G, V,M} 
     g::G
     weights_dict::V
     weights_distribution_matrix::M
-    astubs::Vector{Int}
-    bstubs::Vector{Int}
+    mixing_edges::MixingEdges
+    sample_cache::Matrix{Vector{Int}}
     function WeightedGraph(demographics,demographic_index_vectors,mixing_matrix,weights_distribution_matrix)
-        mixing_contacts = MixingEdges(demographic_index_vectors,mixing_matrix)
+        mixing_edges = MixingEdges(demographic_index_vectors,mixing_matrix)
         g = Graph(length(demographics))
+        graph_from_mixing_edges(g,mixing_edges)
         weights_dict = RobinDict{Tuple{Int,Int},UInt8}()
         sampler_matrix = map(m -> Distributions.PoissonCountSampler.(m),weights_distribution_matrix)
-        astubs,bstubs = random_bipartite_graphs_fast!(g,demographic_index_vectors,mixing_contacts)
+        sample_cache = map(v-> Vector{Int}(undef,length(v[1])),mixing_edges.contact_array)
+
         return new{typeof(g),typeof(weights_dict),typeof(sampler_matrix)}(
             g,
             weights_dict,
             sampler_matrix,
-            astubs,
-            bstubs
+            mixing_edges,
+            sample_cache
         )
     end
-    function WeightedGraph(g::SimpleGraph,weights_distribution_matrix)
-        astubs = Vector{Int}(undef,g.ne)
-        bstubs = Vector{Int}(undef,g.ne)
-        for (k,e) in enumerate(edges(g))
-            astubs[k] = src(e)
-            bstubs[k] = dst(e)
-        end
+    function WeightedGraph(g::SimpleGraph,demographics,demographic_index_vectors,weights_distribution_matrix)
+        mixing_edges = MixingEdges(g, demographics, demographic_index_vectors)
         weights_dict = RobinDict{Tuple{Int,Int},UInt8}()
         sampler_matrix =  map(m -> Distributions.PoissonCountSampler.(m),weights_distribution_matrix)
+        # @show map(t->length.(t), mixing_edges.contact_array)
+        sample_cache = map(v-> Vector{Int}(undef,length(v[1])),mixing_edges.contact_array)
         return new{typeof(g),typeof(weights_dict),typeof(sampler_matrix)}(
             g,
             weights_dict, 
             sampler_matrix,
-            astubs,
-            bstubs
+            mixing_edges,
+            sample_cache
         )
     end
 end
 function Base.show(io::IO, g::WeightedGraph) 
-    print(io, "WG")
+    print(io, "WG $(ne(g.g))")
 end 
 function sample_mixing_graph!(mixing_graph,population_demographics)
-    for k in eachindex(mixing_graph.astubs)
-        i = mixing_graph.astubs[k]
-        j = mixing_graph.bstubs[k]
+    @unpack mixing_edges = mixing_graph
+
+    for i in 1:size(mixing_edges.contact_array)[1], j in 1:i  #diagonal
         demo_i = Int(population_demographics[i])
         demo_j = Int(population_demographics[j])
-        contact_time = rand(RNG, mixing_graph.weights_distribution_matrix[demo_i,demo_j])
-        mixing_graph.weights_dict[(i,j)] = contact_time
-        mixing_graph.weights_dict[(j,i)] = contact_time
+        rand!(RNG, mixing_graph.weights_distribution_matrix[demo_i,demo_j],mixing_graph.sample_cache[i,j])
+        for k in 1:length(mixing_edges.contact_array[i,j][1])
+            kth_node_i = mixing_edges.contact_array[i,j][1][k]
+            kth_node_j = mixing_edges.contact_array[i,j][2][k]
+            edge_weight_k = mixing_graph.sample_cache[i,j][k]
+            mixing_graph.weights_dict[(kth_node_i,kth_node_j)] = edge_weight_k
+            mixing_graph.weights_dict[(kth_node_j,kth_node_i)] = edge_weight_k
+        end
+
     end
 end
 @inline function reindex!(k,csum,index_list_i,index_list_j,j_to_i_contacts,i_to_j_contacts,sample_list_i,sample_list_j)
diff --git a/CovidAlertVaccinationModel/src/ABM/output.jl b/CovidAlertVaccinationModel/src/ABM/output.jl
index 7bd34defba666a5fb640810dadfa2b3dfda81214..61748f47892381dd5e7268c1f9135e54bf6d2ef4 100644
--- a/CovidAlertVaccinationModel/src/ABM/output.jl
+++ b/CovidAlertVaccinationModel/src/ABM/output.jl
@@ -12,12 +12,12 @@ struct DebugRecorder <: AbstractRecorder
     Total_Vaccinator::Vector{Int}
     function DebugRecorder(sim_length)
         return new(
-            zeros(Int,AgentStatus.size,sim_length),
-            zeros(Int,sim_length),
-            zeros(Int,sim_length),
-            zeros(Int,sim_length),
-            zeros(Int,sim_length),
-            zeros(Int,sim_length),
+            Matrix{Int}(undef,AgentStatus.size,sim_length),
+            Vector{Int}(undef,sim_length),
+            Vector{Int}(undef,sim_length),
+            Vector{Int}(undef,sim_length),
+            Vector{Int}(undef,sim_length),
+            Vector{Int}(undef,sim_length),
         )
     end
 end
diff --git a/CovidAlertVaccinationModel/src/ABM/solve.jl b/CovidAlertVaccinationModel/src/ABM/solve.jl
index 8926e22ca2272474b9026fb684675c2d81f5c173..efcd7360c3e471a93840fc615772f9686642e264 100644
--- a/CovidAlertVaccinationModel/src/ABM/solve.jl
+++ b/CovidAlertVaccinationModel/src/ABM/solve.jl
@@ -12,6 +12,7 @@ function update_alert_durations!(t,modelsol)
             covid_alert_times[i,j-1] = covid_alert_times[i,j] #shift them all back  
         end
         for j in neighbors(mixing_graph.g,node)
+            
             if app_user[j] 
                 covid_alert_times[i,end] += mixing_graph.weights_dict[(node,j)] #add the contact times for today to the back
             end
@@ -26,6 +27,7 @@ function update_infection_state!(t,modelsol)
     @unpack u_inf,u_vac,u_next_inf,u_next_vac,demographics,inf_network,status_totals = modelsol
     
     function agent_transition!(node, from::AgentStatus,to::AgentStatus) 
+        # @show ((from,to))
         status_totals[Int(from)] -= 1
         status_totals[Int(to)] += 1
         u_next_inf[node] = to
@@ -44,6 +46,8 @@ function update_infection_state!(t,modelsol)
                     for j in neighbors(mixing_graph.g,i)    
                         if u_inf[j] == Infected && u_next_inf[i] != Infected 
                             if rand(RNG) < contact_weight(base_transmission_probability,mixing_graph.weights_dict[(i,j)])
+                         
+                                
                                 agent_transition!(i, Susceptible,Infected)
                             end
                         end
@@ -60,6 +64,7 @@ function update_infection_state!(t,modelsol)
             end
         end
     end
+    # display(u_next_inf)
 end
 function update_vaccination_opinion_state!(t,modelsol,total_infections)
     
@@ -122,7 +127,6 @@ function agents_step!(t,modelsol)
 
     modelsol.u_vac .= modelsol.u_next_vac
     modelsol.u_inf .= modelsol.u_next_inf
-    # modelsol.status_totals .= modelsol.status_totals_next
 end