def test_axpby(self): # test axpby between BlockDataContainers ig0 = ImageGeometry(2, 3, 4) ig1 = ImageGeometry(2, 3, 5) data0 = ig0.allocate(-1) data2 = ig0.allocate(1) data1 = ig0.allocate(2) data3 = ig0.allocate(3) cp0 = BlockDataContainer(data0, data2) cp1 = BlockDataContainer(data1, data3) out = cp0 * 0. - 10 cp0.axpby(3, -2, cp1, out, num_threads=4) # operation should be [ 3 * -1 + (-2) * 2 , 3 * 1 + (-2) * 3 ] # output should be [ -7 , -3 ] res0 = ig0.allocate(-7) res2 = ig0.allocate(-3) res = BlockDataContainer(res0, res2) print("res0", res0.as_array()) print("res2", res2.as_array()) print("###############################") print("out_0", out.get_item(0).as_array()) print("out_1", out.get_item(1).as_array()) self.assertBlockDataContainerEqual(out, res)
def test_FISTA_Norm2Sq(self): print ("Test FISTA Norm2Sq") ig = ImageGeometry(127,139,149) b = ig.allocate(ImageGeometry.RANDOM) # fill with random numbers x_init = ig.allocate(ImageGeometry.RANDOM) identity = Identity(ig) #### it seems FISTA does not work with Nowm2Sq norm2sq = LeastSquares(identity, b) #norm2sq.L = 2 * norm2sq.c * identity.norm()**2 #norm2sq = FunctionOperatorComposition(L2NormSquared(b=b), identity) opt = {'tol': 1e-4, 'memopt':False} print ("initial objective", norm2sq(x_init)) alg = FISTA(x_init=x_init, f=norm2sq, g=ZeroFunction()) alg.max_iteration = 2 alg.run(20, verbose=True) self.assertNumpyArrayAlmostEqual(alg.x.as_array(), b.as_array()) alg = FISTA(x_init=x_init, f=norm2sq, g=ZeroFunction(), max_iteration=2, update_objective_interval=3) self.assertTrue(alg.max_iteration == 2) self.assertTrue(alg.update_objective_interval== 3) alg.run(20, verbose=True) self.assertNumpyArrayAlmostEqual(alg.x.as_array(), b.as_array())
def test_mixedL12Norm(self): M, N, K = 2, 3, 5 ig = ImageGeometry(voxel_num_x=M, voxel_num_y=N) u1 = ig.allocate('random_int') u2 = ig.allocate('random_int') U = BlockDataContainer(u1, u2, shape=(2, 1)) # Define no scale and scaled f_no_scaled = MixedL21Norm() f_scaled = 1 * MixedL21Norm() # call a1 = f_no_scaled(U) a2 = f_scaled(U) self.assertNumpyArrayAlmostEqual(a1, a2) tmp = [el**2 for el in U.containers] self.assertBlockDataContainerEqual(BlockDataContainer(*tmp), U.power(2)) z1 = f_no_scaled.proximal_conjugate(U, 1) u3 = ig.allocate('random_int') u4 = ig.allocate('random_int') z3 = BlockDataContainer(u3, u4, shape=(2, 1)) f_no_scaled.proximal_conjugate(U, 1, out=z3) self.assertBlockDataContainerEqual(z3, z1)
def test_ImageDataSubset(self): new_order = ['horizontal_x', 'channel', 'horizontal_y', ] vgeometry = ImageGeometry(voxel_num_x=4, voxel_num_y=3, channels=2, dimension_labels=new_order) # expected dimension_labels self.assertListEqual(new_order, vgeometry.dimension_labels) vol = vgeometry.allocate() # test reshape new_order = [ 'channel', 'horizontal_x','horizontal_y'] ss = vol.subset(new_order) self.assertListEqual(new_order, ss.geometry.dimension_labels) ss1 = ss.subset(horizontal_x = 0) self.assertListEqual([ 'channel', 'horizontal_y'], ss1.geometry.dimension_labels) vg = ImageGeometry(3,4,5,channels=2) self.assertListEqual([ImageGeometry.CHANNEL, ImageGeometry.VERTICAL, ImageGeometry.HORIZONTAL_Y, ImageGeometry.HORIZONTAL_X], vg.dimension_labels) ss2 = vg.allocate() ss3 = ss2.subset(vertical = 0, channel=0) self.assertListEqual([ImageGeometry.HORIZONTAL_Y, ImageGeometry.HORIZONTAL_X], ss3.geometry.dimension_labels)
def test_ImageData(self): # create ImageData from geometry vgeometry = ImageGeometry(voxel_num_x=4, voxel_num_y=3, channels=2) #vol = ImageData(geometry=vgeometry) vol = vgeometry.allocate() self.assertEqual(vol.shape, (2, 3, 4)) vol1 = vol + 1 self.assertNumpyArrayEqual(vol1.as_array(), numpy.ones(vol.shape)) vol1 = vol - 1 self.assertNumpyArrayEqual(vol1.as_array(), -numpy.ones(vol.shape)) vol1 = 2 * (vol + 1) self.assertNumpyArrayEqual(vol1.as_array(), 2 * numpy.ones(vol.shape)) vol1 = (vol + 1) / 2 self.assertNumpyArrayEqual(vol1.as_array(), numpy.ones(vol.shape) / 2) vol1 = vol + 1 self.assertEqual(vol1.sum(), 2*3*4) vol1 = (vol + 2) ** 2 self.assertNumpyArrayEqual(vol1.as_array(), numpy.ones(vol.shape) * 4) self.assertEqual(vol.number_of_dimensions, 3) ig2 = ImageGeometry (voxel_num_x=2,voxel_num_y=3,voxel_num_z=4, dimension_labels=[ImageGeometry.HORIZONTAL_X, ImageGeometry.HORIZONTAL_Y, ImageGeometry.VERTICAL]) data = ig2.allocate() self.assertNumpyArrayEqual(numpy.asarray(data.shape), numpy.asarray(ig2.shape)) self.assertNumpyArrayEqual(numpy.asarray(data.shape), data.as_array().shape)
def test_GradientDescentArmijo(self): print ("Test GradientDescent") ig = ImageGeometry(12,13,14) x_init = ig.allocate() # b = x_init.copy() # fill with random numbers # b.fill(numpy.random.random(x_init.shape)) b = ig.allocate('random') identity = Identity(ig) norm2sq = LeastSquares(identity, b) rate = None alg = GradientDescent(x_init=x_init, objective_function=norm2sq, rate=rate) alg.max_iteration = 100 alg.run() self.assertNumpyArrayAlmostEqual(alg.x.as_array(), b.as_array()) alg = GradientDescent(x_init=x_init, objective_function=norm2sq, max_iteration=20, update_objective_interval=2) #alg.max_iteration = 20 self.assertTrue(alg.max_iteration == 20) self.assertTrue(alg.update_objective_interval==2) alg.run(20, verbose=True) self.assertNumpyArrayAlmostEqual(alg.x.as_array(), b.as_array())
def test_FISTA_catch_Lipschitz(self): print ("Test FISTA catch Lipschitz") ig = ImageGeometry(127,139,149) x_init = ImageData(geometry=ig) x_init = ig.allocate() b = x_init.copy() # fill with random numbers b.fill(numpy.random.random(x_init.shape)) x_init = ig.allocate(ImageGeometry.RANDOM) identity = Identity(ig) #### it seems FISTA does not work with Nowm2Sq norm2sq = LeastSquares(identity, b) print ('Lipschitz', norm2sq.L) norm2sq.L = None #norm2sq.L = 2 * norm2sq.c * identity.norm()**2 #norm2sq = FunctionOperatorComposition(L2NormSquared(b=b), identity) opt = {'tol': 1e-4, 'memopt':False} print ("initial objective", norm2sq(x_init)) try: alg = FISTA(x_init=x_init, f=norm2sq, g=ZeroFunction()) self.assertTrue(False) except ValueError as ve: print (ve) self.assertTrue(True)
def test_axpby2(self): # test axpby with BlockDataContainer and DataContainer ig0 = ImageGeometry(2, 3, 4) # ig1 = ImageGeometry(2,3,5) data0 = ig0.allocate(-1) data2 = ig0.allocate(1) data1 = ig0.allocate(2) # data3 = ig1.allocate(3) cp0 = BlockDataContainer(data0, data2) # cp1 = BlockDataContainer(data1,data3) out = cp0 * 0. - 10 cp0.axpby(3, -2, data1, out) # operation should be [ 3 * -1 + (-2) * 2 , 3 * 1 + (-2) * 2 ] # output should be [ -7 , -1 ] res0 = ig0.allocate(-7) res2 = ig0.allocate(-1) res = BlockDataContainer(res0, res2) print("res0", res0.as_array()) print("res2", res2.as_array()) print("###############################") print("out_0", out.get_item(0).as_array()) print("out_1", out.get_item(1).as_array()) self.assertBlockDataContainerEqual(out, res)
def test_CGLS(self): print ("Test CGLS") #ig = ImageGeometry(124,153,154) ig = ImageGeometry(10,2) numpy.random.seed(2) x_init = ig.allocate(0.) b = ig.allocate('random') # b = x_init.copy() # fill with random numbers # b.fill(numpy.random.random(x_init.shape)) # b = ig.allocate() # bdata = numpy.reshape(numpy.asarray([i for i in range(20)]), (2,10)) # b.fill(bdata) identity = Identity(ig) alg = CGLS(x_init=x_init, operator=identity, data=b) alg.max_iteration = 200 alg.run(20, verbose=True) self.assertNumpyArrayAlmostEqual(alg.x.as_array(), b.as_array()) alg = CGLS(x_init=x_init, operator=identity, data=b, max_iteration=200, update_objective_interval=2) self.assertTrue(alg.max_iteration == 200) self.assertTrue(alg.update_objective_interval==2) alg.run(20, verbose=True) self.assertNumpyArrayAlmostEqual(alg.x.as_array(), b.as_array())
def test_axpby(self): print ("test axpby") ig = ImageGeometry(10,10) d1 = ig.allocate(1) d2 = ig.allocate(2) out = ig.allocate(None) # equals to 2 * [1] + 1 * [2] = [4] d1.axpby(2,1,d2,out) res = numpy.ones_like(d1.as_array()) * 4. numpy.testing.assert_array_equal(res, out.as_array())
def test_axpby2(self): print ("test axpby2") N = 100 ig = ImageGeometry(N,2*N,N*10) d1 = ig.allocate(1) d2 = ig.allocate(2) out = ig.allocate(None) print ("allocated") # equals to 2 * [1] + 1 * [2] = [4] d1.axpby(2,1,d2,out, num_threads=4) print ("calculated") res = numpy.ones_like(d1.as_array()) * 4. numpy.testing.assert_array_equal(res, out.as_array())
def test_ImageGeometry_allocate(self): vgeometry = ImageGeometry(voxel_num_x=4, voxel_num_y=3, channels=2) image = vgeometry.allocate() self.assertEqual(0,image.as_array()[0][0][0]) image = vgeometry.allocate(1) self.assertEqual(1,image.as_array()[0][0][0]) default_order = ['channel' , 'horizontal_y' , 'horizontal_x'] self.assertEqual(default_order[0], image.dimension_labels[0]) self.assertEqual(default_order[1], image.dimension_labels[1]) self.assertEqual(default_order[2], image.dimension_labels[2]) order = [ 'horizontal_x' , 'horizontal_y', 'channel' ] image = vgeometry.allocate(0,dimension_labels=order) self.assertEqual(order[0], image.dimension_labels[0]) self.assertEqual(order[1], image.dimension_labels[1]) self.assertEqual(order[2], image.dimension_labels[2])
def stest_NestedBlockDataContainer2(self): M, N = 2, 3 ig = ImageGeometry(voxel_num_x=M, voxel_num_y=N) ag = ig u = ig.allocate(1) op1 = Gradient(ig) op2 = Identity(ig, ag) operator = BlockOperator(op1, op2, shape=(2, 1)) d1 = op1.direct(u) d2 = op2.direct(u) d = operator.direct(u) dd = operator.domain_geometry() ww = operator.range_geometry() print(d.get_item(0).get_item(0).as_array()) print(d.get_item(0).get_item(1).as_array()) print(d.get_item(1).as_array()) c1 = d + d c2 = 2 * d c3 = d / (d + 0.0001) c5 = d.get_item(0).power(2).sum()
def test_Norm(self): print ("test_BlockOperator") ## numpy.random.seed(1) N, M = 200, 300 ig = ImageGeometry(N, M) G = Gradient(ig) t0 = timer() norm = G.norm() t1 = timer() norm2 = G.norm() t2 = timer() norm3 = G.norm(force=True) t3 = timer() print ("Norm dT1 {} dT2 {} dT3 {}".format(t1-t0,t2-t1, t3-t2)) self.assertLess(t2-t1, t1-t0) self.assertLess(t2-t1, t3-t2) numpy.random.seed(1) t4 = timer() norm4 = G.norm(iterations=50, force=True) t5 = timer() self.assertLess(t2-t1, t5-t4) numpy.random.seed(1) t4 = timer() norm5 = G.norm(x_init=ig.allocate('random'), iterations=50, force=True) t5 = timer() self.assertLess(t2-t1, t5-t4) for n in [norm, norm2, norm3, norm4, norm5]: print ("norm {}", format(n))
def test_ScaledOperator(self): print ("test_ScaledOperator") ig = ImageGeometry(10,20,30) img = ig.allocate() scalar = 0.5 sid = scalar * Identity(ig) numpy.testing.assert_array_equal(scalar * img.as_array(), sid.direct(img).as_array())
def test_BlockOperatorLinearValidity(self): print ("test_BlockOperatorLinearValidity") M, N = 3, 4 ig = ImageGeometry(M, N) arr = ig.allocate('random_int') G = Gradient(ig) Id = Identity(ig) B = BlockOperator(G, Id) # Nx1 case u = ig.allocate('random_int') w = B.range_geometry().allocate(ImageGeometry.RANDOM_INT) w1 = B.direct(u) u1 = B.adjoint(w) self.assertEqual((w * w1).sum() , (u1*u).sum())
def test_max(self): print ("test max") ig = ImageGeometry(10,10) a = numpy.asarray(numpy.linspace(-10,10, num=100, endpoint=True), dtype=numpy.float32) a = a.reshape((10,10)) d1 = ig.allocate(1) d1.fill(a) self.assertAlmostEqual(d1.max(), 10.)
def test_Norm2sq_as_FunctionOperatorComposition(self): print('Test for FunctionOperatorComposition') M, N = 50, 50 ig = ImageGeometry(voxel_num_x=M, voxel_num_y=N) b = ig.allocate('random_int') print('Check call with Identity operator... OK\n') operator = 3 * Identity(ig) u = ig.allocate('random_int', seed=50) func1 = FunctionOperatorComposition(0.5 * L2NormSquared(b=b), operator) func2 = LeastSquares(operator, b, 0.5) self.assertNumpyArrayAlmostEqual(func1(u), func2(u)) print('Check gradient with Identity operator... OK\n') tmp1 = ig.allocate() tmp2 = ig.allocate() res_gradient1 = func1.gradient(u) res_gradient2 = func2.gradient(u) func1.gradient(u, out=tmp1) func2.gradient(u, out=tmp2) self.assertNumpyArrayAlmostEqual(tmp1.as_array(), tmp2.as_array()) self.assertNumpyArrayAlmostEqual(res_gradient1.as_array(), res_gradient2.as_array()) print('Check call with LinearOperatorMatrix... OK\n') mat = np.random.randn(M, N) operator = LinearOperatorMatrix(mat) vg = VectorGeometry(N) b = vg.allocate('random_int') u = vg.allocate('random_int') func1 = FunctionOperatorComposition(0.5 * L2NormSquared(b=b), operator) func2 = LeastSquares(operator, b, 0.5) self.assertNumpyArrayAlmostEqual(func1(u), func2(u)) self.assertNumpyArrayAlmostEqual(func1.L, func2.L)
def testwriteImageData(self): im_size = 5 ig = ImageGeometry(voxel_num_x = im_size, voxel_num_y = im_size) im = ig.allocate() writer = NEXUSDataWriter() writer.set_up(file_name = os.path.join(os.getcwd(), 'test_nexus_im.nxs'), data_container = im) writer.write_file() self.stestreadImageData()
def test_Identity(self): print ("test_Identity") ig = ImageGeometry(10,20,30) img = ig.allocate() # img.fill(numpy.ones((30,20,10))) self.assertTrue(img.shape == (30,20,10)) #self.assertEqual(img.sum(), 2*float(10*20*30)) self.assertEqual(img.sum(), 0.) Id = Identity(ig) y = Id.direct(img) numpy.testing.assert_array_equal(y.as_array(), img.as_array())
def test_IndicatorBox(self): ig = ImageGeometry(10, 10) im = ig.allocate(-1) ib = IndicatorBox(lower=0) a = ib(im) numpy.testing.assert_equal(a, numpy.inf) ib = IndicatorBox(lower=-2) a = ib(im) numpy.testing.assert_array_equal(0, a) ib = IndicatorBox(lower=-5, upper=-2) a = ib(im) numpy.testing.assert_equal(a, numpy.inf)
def test_ImageGeometry_allocate(self): vgeometry = ImageGeometry(voxel_num_x=4, voxel_num_y=3, channels=2) image = vgeometry.allocate() self.assertEqual(0,image.as_array()[0][0][0]) image = vgeometry.allocate(1) self.assertEqual(1,image.as_array()[0][0][0]) default_order = ['channel' , 'horizontal_y' , 'horizontal_x'] self.assertEqual(default_order[0], image.dimension_labels[0]) self.assertEqual(default_order[1], image.dimension_labels[1]) self.assertEqual(default_order[2], image.dimension_labels[2]) order = [ 'horizontal_x' , 'horizontal_y', 'channel' ] image = vgeometry.allocate(0,dimension_labels=order) self.assertEqual(order[0], image.dimension_labels[0]) self.assertEqual(order[1], image.dimension_labels[1]) self.assertEqual(order[2], image.dimension_labels[2]) ig = ImageGeometry(2,3,2) try: z = ImageData(numpy.random.randint(10, size=(2,3)), geometry=ig) self.assertTrue(False) except ValueError as ve: print (ve) self.assertTrue(True)
def stestreadImageData(self): im_size = 5 ig_test = ImageGeometry(voxel_num_x = im_size, voxel_num_y = im_size) im_test = ig_test.allocate() reader = NEXUSDataReader() reader.set_up(nexus_file = os.path.join(os.getcwd(), 'test_nexus_im.nxs')) im = reader.load_data() ig = reader.get_geometry() numpy.testing.assert_array_equal(im.as_array(), im_test.as_array(), 'Loaded image is not correct') self.assertEqual(ig.voxel_num_x, ig_test.voxel_num_x, 'ImageGeometry is not correct') self.assertEqual(ig.voxel_num_y, ig_test.voxel_num_y, 'ImageGeometry is not correct')
def test_NestedBlockDataContainer(self): ig0 = ImageGeometry(2, 3, 4) ig1 = ImageGeometry(2, 3, 5) data0 = ig0.allocate(0) data2 = ig0.allocate(1) cp0 = BlockDataContainer(data0, data2) #cp1 = BlockDataContainer(data2,data3) nested = BlockDataContainer(cp0, data2, data2) out = BlockDataContainer(BlockDataContainer(data0, data0), data0, data0) nested.divide(data2, out=out) self.assertBlockDataContainerEqual(out, nested)
def test_multiply_out(self): print ("test multiply_out") import functools ig = ImageGeometry(10,11,12) u = ig.allocate() a = numpy.ones(u.shape) u.fill(a) numpy.testing.assert_array_equal(a, u.as_array()) #u = ig.allocate(ImageGeometry.RANDOM_INT, seed=1) l = functools.reduce(lambda x,y: x*y, (10,11,12), 1) a = numpy.zeros((l, ), dtype=numpy.float32) for i in range(l): a[i] = numpy.sin(2 * i* 3.1415/l) b = numpy.reshape(a, u.shape) u.fill(b) numpy.testing.assert_array_equal(b, u.as_array()) u.multiply(2, out=u) c = b * 2 numpy.testing.assert_array_equal(u.as_array(), c)
def test_axpby4(self): # test axpby with nested BlockDataContainer ig0 = ImageGeometry(2, 3, 4) ig1 = ImageGeometry(2, 3, 5) data0 = ig0.allocate(-1) data2 = ig0.allocate(1) # data1 = ig0.allocate(2) data3 = ig1.allocate(3) cp0 = BlockDataContainer(data0, data2) cp1 = BlockDataContainer(cp0 * 0. + [2, -2], data3) print(cp1.get_item(0).get_item(0).as_array()) print(cp1.get_item(0).get_item(1).as_array()) print(cp1.get_item(1).as_array()) print("###############################") out = cp1 * 0. cp2 = out + [1, 3] print(cp2.get_item(0).get_item(0).as_array()) print(cp2.get_item(0).get_item(1).as_array()) print(cp2.get_item(1).as_array()) cp2.axpby(3, -2, cp1, out, num_threads=4) # output should be [ [ -1 , 7 ] , 3] res0 = ig0.allocate(-1) res2 = ig0.allocate(7) res3 = ig1.allocate(3) res = BlockDataContainer(BlockDataContainer(res0, res2), res3) # print ("res0", res0.as_array()) # print ("res2", res2.as_array()) print("###############################") # print ("out_0", out.get_item(0).as_array()) # print ("out_1", out.get_item(1).as_array()) self.assertBlockDataContainerEqual(out, res)
if False: N = 100 ig2D = ImageGeometry(voxel_num_x=N, voxel_num_y=N) ig3D = ImageGeometry(voxel_num_x=N, voxel_num_y=N, voxel_num_z=N) ch_number = 10 ig2D_ch = ImageGeometry(voxel_num_x=N, voxel_num_y=N, channels=ch_number) ig3D_ch = ImageGeometry(voxel_num_x=N, voxel_num_y=N, voxel_num_z=N, channels=ch_number) x2D = ig2D.allocate('random_int') x2D_ch = ig2D_ch.allocate('random_int') x3D = ig3D.allocate('random_int') x3D_ch = ig3D_ch.allocate('random_int') #%% ############################################################################### # test 2D cases show(x2D) show(x2D, title='2D no font') show(x2D, title='2D with font', font_size=(50, 30)) show(x2D, title='2D with font/fig_size', font_size=(20, 10), figure_size=(10, 10)) show(x2D,
else: self.proximal(x / tau, tau, out=out) out *= -1 * tau out += x if __name__ == '__main__': from ccpi.framework import ImageGeometry, BlockDataContainer N, M = 2, 3 ig = ImageGeometry(voxel_num_x=N, voxel_num_y=M) u = ig.allocate('random_int') tau = 2 f = IndicatorBox(2, 3) lower = 10 upper = 30 z1 = f.proximal(u, tau) z2 = f.proximal_conjugate(u / tau, 1 / tau) z = z1 + tau * z2 numpy.testing.assert_array_equal(z.as_array(), u.as_array())
# else: # if self.b is not None: # x.subtract(tau*self.b, out=out) # out.divide(1+tau/2, out=out) # else: # x.divide(1 + tau/2, out=out) if __name__ == '__main__': from ccpi.framework import ImageGeometry import numpy # TESTS for L2 and scalar * L2 M, N, K = 2,3,1 ig = ImageGeometry(voxel_num_x=M, voxel_num_y = N, voxel_num_z = K) u = ig.allocate('random_int') b = ig.allocate('random_int') # check grad/call no data f = L2NormSquared() a1 = f.gradient(u) a2 = 2 * u numpy.testing.assert_array_almost_equal(a1.as_array(), a2.as_array(), decimal=4) numpy.testing.assert_equal(f(u), u.squared_norm()) # check grad/call with data igggg = ImageGeometry(4,4) f1 = L2NormSquared(b=b) b1 = f1.gradient(u) b2 = 2 * (u-b)
fb, axarrb = plt.subplots(1, numchannels) for k in numpy.arange(3): axarrb[k].imshow(b.as_array()[k], vmin=0, vmax=250) plt.show() z = Aop.adjoint(b) fo, axarro = plt.subplots(1, numchannels) for k in range(3): axarro[k].imshow(z.as_array()[k], vmin=0, vmax=3500) plt.show() # Using the test data b, different reconstruction methods can now be set up as # demonstrated in the rest of this file. In general all methods need an initial # guess and some algorithm options to be set: x_init = ig.allocate(0.0) opt = {'tol': 1e-4, 'iter': 200} # Create least squares object instance with projector, test data and a constant # coefficient of 0.5. Note it is least squares over all channels: #f = Norm2Sq(Aop,b,c=0.5) f = FunctionOperatorComposition(L2NormSquared(b=b), Aop) # Run FISTA for least squares without regularization FISTA_alg = FISTA() FISTA_alg.set_up(x_init=x_init, f=f, g=ZeroFunction()) FISTA_alg.max_iteration = 2000 FISTA_alg.run(opt['iter']) x_FISTA = FISTA_alg.get_output() # Display reconstruction and criterion ff0, axarrf0 = plt.subplots(1, numchannels)