diff --git a/cfg_utils.py b/cfg_utils.py
index 4de2989b6ad6be5ab3889ef691bdd95232b798af..d7843d39e8d220759edfdaa9c6e20af2a0c10aee 100644
--- a/cfg_utils.py
+++ b/cfg_utils.py
@@ -507,10 +507,10 @@ class CFGBoltzmann:
     # by the integer at each element.
 
     def normalized_choice(self, inlist):
-        total_weight = sum(inlist)
-        weights = [x / total_weight for x in inlist]
-        choice = random.choices(range(len(inlist)), weights=weights)
-        return choice
+        #total_weight = sum(inlist)
+        #weights = [x / total_weight for x in inlist]
+        choice = random.choices(range(len(inlist)), weights=inlist)
+        return choice[0]
 
 
     # Similar to Fzero and Fprim, we have Gzero and Gprim.
@@ -522,7 +522,9 @@ class CFGBoltzmann:
     def Gzero(self, nonterminal_index, requested_length):
         possibilities = self.Fzero(nonterminal_index, requested_length)
         chosen_production = self.normalized_choice(possibilities)
-        generated_string - self.Gprim(nonterminal_index, chosen_production, 1, requested_length)
+        generated_string = self.Gprim(nonterminal_index, chosen_production, 1, requested_length)
+
+        return generated_string
 
     # Like Fprim, Gprim takes a nonterminal index, a production index for the nonterminal,
     # and an index into the production rule (and of course, a requested length).
@@ -559,8 +561,76 @@ class CFGBoltzmann:
     #                        \----------------------------------------------------------/
 
 
-    def Gprim(self, nonterminal_index, chosen_production, how_far_into_the_RHS, requested_length):
-        
+    def Gprim(self, nonterminal_index, chosen_production, how_far_into_the_RHS, exact_length_total):
+        print("arguments are", nonterminal_index, chosen_production, how_far_into_the_RHS, exact_length_total)
+
+        # first, handle the ultimate degenerate case:
+        if (exact_length_total == 0):
+            print("LENGTH ZERO RETURNING \"\"")
+            return ""
+
+        # The case analysis hinges on what is at X_ijk.
+
+        RHS_in_question = self.processed_rulepack[nonterminal_index][1][chosen_production]
+        print("Our RHS is", RHS_in_question)
+        print("WE ARE PROCESSING index", how_far_into_the_RHS, "and our remaining lengthis", exact_length_total)
+
+        xijk = RHS_in_question[how_far_into_the_RHS]
+
+        if (xijk in self.terminals):
+         #   print("xijk", xijk, "is a terminal, hokay")
+        #    print("lenghts of RHS In question is", len(RHS_in_question))
+
+            # are we at the end of the rule
+            if (how_far_into_the_RHS == (len(RHS_in_question) - 1)):
+                # CASE A
+                print("GPRIM CASE A ")
+                return xijk
+            else:
+                # CASE B
+                print("CASE B")
+                reduct = self.Gprim(nonterminal_index, chosen_production, how_far_into_the_RHS + 1, exact_length_total - 1)
+                retstring = xijk + reduct
+                return retstring
+
+
+        else:
+            assert (xijk in self.nonterminals)
+       #     print("xijk", xijk, "is a NONterminal!")
+       #     print("lenghts of RHS In question is", len(RHS_in_question))
+            #print("how far?", how_far_into_the_RHS)
+            ## we now calculate the index of nonterminal at index K, we need it for both cases
+            new_nonterminal_index = self.nonterminals_ordered.index(xijk)
+           # print("NEW NONTERMINAL INDDEX IS", new_nonterminal_index)
+
+            if (how_far_into_the_RHS == (len(RHS_in_question) - 1)):
+                # CASE C
+                print("CASE C")
+                retstring = self.Gzero(new_nonterminal_index, exact_length_total)
+                return retstring
+
+            else:
+                # CASE D
+
+                print("CASE D")
+
+
+                splitting_possibilities = self.Fprim(nonterminal_index, chosen_production, how_far_into_the_RHS, exact_length_total)
+                split_choice = self.normalized_choice(splitting_possibilities)
+
+                # hit the nonterminal X_ijk with Gzero
+
+                nonterminal_generates = self.Gzero(new_nonterminal_index, split_choice)
+
+                # and then the remaining part of the rule
+
+                rest_of_rule_generates = self.Gprim(nonterminal_index, chosen_production, how_far_into_the_RHS, exact_length_total - split_choice)
+
+                retstring = nonterminal_generates + rest_of_rule_generates
+                print ("Gprim returns", retstring)
+                return retstring
+
+
 
 
 
@@ -570,7 +640,7 @@ z = CFGBoltzmann(rules, list_of_nonterminals, list_of_terminals)
 rulepack_cooked = z.preprocessor()
 
 
-print("XXXXXXXXXXXXXXXX", z.Fzero(0, 101))
+print("XXXXXXXXXXXXXXXX", z.Gzero(0, 3))
 
 
 # Furthermore, we also note that the description of a context-free grammar is *itself* context-free