def test_radiation(self): m = 1000 # voxels n = 200 # beams dose = 1.0 A = np.random.rand(m, n) labels = (np.random.rand(m) > 0.2).astype(int) # Dose matrix with target voxels receive ~3x radiation of non-target voxels. # Label 0 = tumor, label 1 = organ-at-risk. FACTOR = 3 for i, label in enumerate(labels): if label == 0: A[i, :] *= FACTOR # Solve radiation treatment planning problem. x = Variable(n) y = Variable(m) y_ptv = y[labels == 0] y_oar = y[labels == 1] obj = sum(neg(y_ptv - dose) + 2 * pos(y_ptv - dose)) + sum( 1.6 * pos(y_oar)) constr = [ A * x == y, x >= 0, quantile(y_ptv, 0.85) >= 0.95, quantile(y_ptv, 0.15) <= 1.0, quantile(y_oar, 0.5) <= 0.35 ] p = Problem(Minimize(obj), constr) # Plot CDF for 1st and 2nd step. p.solve(two_step=False, slack=False) self.plot_cdf(y_oar.value, "b--") self.plot_cdf(y_ptv.value, "r--") p.solve(two_step=True, slack=False) oar, = self.plot_cdf(y_oar.value, "b-") ptv, = self.plot_cdf(y_ptv.value, "r-") # Label constraints on plot. plt.plot(0.95, 0.85, marker=">", markersize=self.markersize, color="red") plt.plot(1.0, 0.15, marker="<", markersize=self.markersize, color="red") plt.plot(0.35, 0.5, marker="<", markersize=self.markersize, color="blue") plt.axvline(dose, color="red", linestyle=":", linewidth=1.0) plt.xlim(0, 1.2) plt.legend([oar, ptv], ["OAR", "PTV"])
def test_constraints(self): obj = norm(self.x) constr = [quantile(self.x, 0.6) <= -1] p = ccprob.Problem(Minimize(obj), constr) p.solve() self.assertTrue( np.sum(self.x.value <= -1 + self.tolerance) >= 0.6 * self.x.size) b = np.abs(np.random.randn(self.x.size)) obj = norm(self.x - b) constr = [quantile(self.x, 0.7) >= 1] p = ccprob.Problem(Minimize(obj), constr) p.solve() self.assertTrue( np.sum(self.x.value >= 1 - self.tolerance) >= np.round(1 - 0.7) * self.x.size)
def test_properties(self): q = quantile(self.x, self.f) self.assertFalse(q.is_atom_convex()) self.assertFalse(q.is_atom_concave()) self.assertTrue(q.is_incr(0)) self.assertFalse(q.is_decr(0)) self.assertFalse(q.is_pwl()) self.assertEqual(quantile(0, self.f).sign_from_args(), (True, True)) self.assertEqual(quantile(1, self.f).sign_from_args(), (True, False)) self.assertEqual(quantile(-1, self.f).sign_from_args(), (False, True)) self.x.value = np.random.randn(10) self.assertEqual(q.sign_from_args(), (False, False)) self.assertItemsAlmostEqual(q.value, np.percentile(self.x.value, 100 * self.f))
def test_reduction_nested(self): # Minimize 2*quantile(y, 0.5)) + 1 # subject to y >= 0. t = Variable() obj = 2 * t + 1 constr = [quantile(self.y, 0.5) <= t, self.y >= 0] p0 = ccprob.Problem(Minimize(obj), constr) p0.solve() y_epi = self.y.value obj = 2 * quantile(self.y, 0.5) + 1 constr = [self.y >= 0] p1 = ccprob.Problem(Minimize(obj), constr) p1.solve() self.assertAlmostEqual(p1.value, p0.value) self.assertItemsAlmostEqual(self.y.value, y_epi) # Minimize -2*quantile(y, 0.75) + 3 # subject to y <= 5. obj = -2 * t + 3 constr = [quantile(self.y, 0.75) >= t, self.y <= 5] p0 = ccprob.Problem(Minimize(obj), constr) p0.solve() y_epi = self.y.value obj = -2 * quantile(self.y, 0.75) + 3 constr = [self.y <= 5] p1 = ccprob.Problem(Minimize(obj), constr) p1.solve() self.assertAlmostEqual(p1.value, p0.value) self.assertItemsAlmostEqual(self.y.value, y_epi) # Minimize quantile(y, 0.75) - quantile(y, 0.5) u = Variable() obj = t - u constr = [ quantile(self.y, 0.75) <= t, quantile(self.y, 0.5) >= u, self.y >= 0, self.y <= 1 ] p0 = ccprob.Problem(Minimize(obj), constr) p0.solve() y_epi = self.y.value obj = quantile(self.y, 0.75) - quantile(self.y, 0.5) constr = [self.y >= 0, self.y <= 1] p1 = ccprob.Problem(Minimize(obj), constr) p1.solve() self.assertAlmostEqual(p1.value, p0.value) self.assertItemsAlmostEqual(self.y.value, y_epi)
def test_reduction_basic(self): # Minimize quantile(y, 0.5) subject to y >= 0. t = Variable() constr = [quantile(self.y, 0.5) <= t, self.y >= 0] p0 = ccprob.Problem(Minimize(t), constr) p0.solve() y_epi = self.y.value obj = quantile(self.y, 0.5) constr = [self.y >= 0] p1 = ccprob.Problem(Minimize(obj), constr) p1.solve() self.assertAlmostEqual(p1.value, p0.value) self.assertItemsAlmostEqual(self.y.value, y_epi) # Maximize quantile(y, 0.75) subject to y <= 5. constr = [quantile(self.y, 0.75) >= t, self.y <= 5] p0 = ccprob.Problem(Maximize(t), constr) p0.solve() y_epi = self.y.value obj = quantile(self.y, 0.75) constr = [self.y <= 5] p1 = ccprob.Problem(Maximize(obj), constr) p1.solve() self.assertAlmostEqual(p1.value, p0.value) self.assertItemsAlmostEqual(self.y.value, y_epi) # Minimize quantile(abs(A*x - b), 0.5) # subject to 0 <= x <= 1, # quantile(x, 0.25) >= 0.1 b = np.random.randn(self.A.shape[0]) constr = [ quantile(abs(self.A * self.x - b), 0.5) <= t, self.x >= 0, self.x <= 1, quantile(self.x, 0.25) >= 0.1 ] p0 = ccprob.Problem(Minimize(t), constr) p0.solve() x_epi = self.x.value obj = quantile(abs(self.A * self.x - b), 0.5) constr = [self.x >= 0, self.x <= 1, quantile(self.x, 0.25) >= 0.1] p1 = ccprob.Problem(Minimize(obj), constr) p1.solve() self.assertAlmostEqual(p1.value, p0.value) self.assertItemsAlmostEqual(self.x.value, x_epi)
def test_radiation_slack(self): m = 1000 # voxels n = 200 # beams dose = 1.0 A = np.random.rand(m, n) labels = (np.random.rand(m) > 0.2).astype(int) # Dose matrix with target voxels receive ~3x radiation of non-target voxels. # Label 0 = tumor, label 1 = organ-at-risk. FACTOR = 3 for i, label in enumerate(labels): if label == 0: A[i, :] *= FACTOR # Solve radiation treatment planning problem. x = Variable(n) y = Variable(m) y_ptv = y[labels == 0] y_oar = y[labels == 1] obj = sum(2.5 * neg(y_ptv - dose) + 5 * pos(y_ptv - dose)) + sum( 1.6 * pos(y_oar)) constr = [ A * x == y, x >= 0, quantile(y_ptv, 0.85) >= 0.95, quantile(y_ptv, 0.15) <= 1.0 ] p = Problem(Minimize(obj), constr) p.solve(two_step=True, slack=False) # Plot CDF of 2-step solution. # self.plot_cdf(y_oar.value, "b-") # self.plot_cdf(y_ptv.value, "r-") plt.plot(0.95, 0.85, marker=">", markersize=self.markersize, color="red") plt.plot(1.0, 0.15, marker="<", markersize=self.markersize, color="red") # plt.show() # First pass infeasible with additional constraint. constr += [quantile(y_oar, 0.3) <= 0.15] p = Problem(Minimize(obj), constr) with self.assertRaises(SolverError) as cm: p.solve(slack=False) # Plot CDF of slack solution with constraint. p.solve(two_step=False, slack=True) self.plot_cdf(y_oar.value, "b--") self.plot_cdf(y_ptv.value, "r--") qt = quantile(y_oar, 0.3).value print("OAR quantile with slack:", qt) p.solve(two_step=True, slack=True) oar, = self.plot_cdf(y_oar.value, "b-") ptv, = self.plot_cdf(y_ptv.value, "r-") # Label original and slack bound. plt.plot([0.15, qt], [0.3, 0.3], "b-") plt.plot(qt, 0.3, marker="<", markersize=self.markersize, color="blue", markerfacecolor="white", markeredgecolor="blue") plt.plot(0.15, 0.3, marker="<", markersize=self.markersize, color="blue") plt.axvline(dose, color="red", linestyle=":", linewidth=1.0) plt.xlim(0, 1.2) plt.legend([oar, ptv], ["OAR", "PTV"])