changeset 29845:2ef9080ca017

allow more mixed-type assignments to work for sparse matrices (bug #60859) This change allows indexed assignment to work when the LHS is a sparse matrix (real or complex) and the RHS is a single precision scalar or matrix (real or complex). * ov-base-sparse.h, ov-base-sparse.cc (octave_base_sparse<T>::assign): Declare RHS as a template type separate from the type of the sparse array itself. Move implementation to header file so that instantiation will work automatically. * Sparse.cc, Sparse.h (Sparse<T>::assign): Provide versions for scalar RHS. * op-scm-cm.cc, op-scm-cs.cc, op-scm-m.cc, op-scm-s.cc, op-sm-cm.cc, op-sm-cs.cc, op-sm-m.cc, op-sm-s.cc: Use DEFNDASSIGNOP_FN to define functions for assignment. Define and install mixed-type assignment operations for float and float complex scalar and array assignments to complex and double sparse arrays. * test/sparse-assign.tst: New tests. * test/module.mk: Update.
author John W. Eaton <jwe@octave.org>
date Wed, 30 Jun 2021 17:52:03 -0400
parents ceb2259f7c11
children 449599fdbad8
files libinterp/octave-value/ov-base-sparse.cc libinterp/octave-value/ov-base-sparse.h libinterp/operators/op-scm-cm.cc libinterp/operators/op-scm-cs.cc libinterp/operators/op-scm-m.cc libinterp/operators/op-scm-s.cc libinterp/operators/op-sm-cm.cc libinterp/operators/op-sm-cs.cc libinterp/operators/op-sm-m.cc libinterp/operators/op-sm-s.cc liboctave/array/Sparse.cc liboctave/array/Sparse.h test/module.mk test/sparse-assign.tst
diffstat 14 files changed, 448 insertions(+), 115 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/octave-value/ov-base-sparse.cc	Thu Jul 01 15:28:17 2021 +0200
+++ b/libinterp/octave-value/ov-base-sparse.cc	Wed Jun 30 17:52:03 2021 -0400
@@ -179,59 +179,6 @@
   return retval;
 }
 
-template <typename T>
-void
-octave_base_sparse<T>::assign (const octave_value_list& idx, const T& rhs)
-{
-
-  octave_idx_type len = idx.length ();
-
-  // If we catch an indexing error in index_vector, we flag an error in
-  // index k.  Ensure it is the right value before each idx_vector call.
-  // Same variable as used in the for loop in the default case.
-
-  octave_idx_type k = 0;
-
-  try
-    {
-      switch (len)
-        {
-        case 1:
-          {
-            octave::idx_vector i = idx (0).index_vector ();
-
-            matrix.assign (i, rhs);
-
-            break;
-          }
-
-        case 2:
-          {
-            octave::idx_vector i = idx (0).index_vector ();
-
-            k = 1;
-            octave::idx_vector j = idx (1).index_vector ();
-
-            matrix.assign (i, j, rhs);
-
-            break;
-          }
-
-        default:
-          error ("sparse indexing needs 1 or 2 indices");
-        }
-    }
-  catch (octave::index_exception& ie)
-    {
-      // Rethrow to allow more info to be reported later.
-      ie.set_pos_if_unset (len, k+1);
-      throw;
-    }
-
-  // Invalidate matrix type.
-  typ.invalidate_type ();
-}
-
 template <typename MT>
 void
 octave_base_sparse<MT>::delete_elements (const octave_value_list& idx)
--- a/libinterp/octave-value/ov-base-sparse.h	Thu Jul 01 15:28:17 2021 +0200
+++ b/libinterp/octave-value/ov-base-sparse.h	Wed Jun 30 17:52:03 2021 -0400
@@ -110,7 +110,56 @@
   // can also cause some confusion.
   using octave_base_value::assign;
 
-  OCTINTERP_API void assign (const octave_value_list& idx, const T& rhs);
+  template <typename RHS_T>
+  OCTINTERP_API void assign (const octave_value_list& idx, const RHS_T& rhs)
+  {
+    octave_idx_type len = idx.length ();
+
+    // If we catch an indexing error in index_vector, we flag an error in
+    // index k.  Ensure it is the right value before each idx_vector call.
+    // Same variable as used in the for loop in the default case.
+
+    octave_idx_type k = 0;
+
+    try
+      {
+        switch (len)
+          {
+          case 1:
+            {
+              octave::idx_vector i = idx (0).index_vector ();
+
+              matrix.assign (i, rhs);
+
+              break;
+            }
+
+          case 2:
+            {
+              octave::idx_vector i = idx (0).index_vector ();
+
+              k = 1;
+              octave::idx_vector j = idx (1).index_vector ();
+
+              matrix.assign (i, j, rhs);
+
+              break;
+            }
+
+          default:
+            error ("sparse indexing needs 1 or 2 indices");
+          }
+      }
+    catch (octave::index_exception& ie)
+      {
+        // Rethrow to allow more info to be reported later.
+        ie.set_pos_if_unset (len, k+1);
+        throw;
+      }
+
+    // Invalidate matrix type.
+    typ.invalidate_type ();
+  }
 
   OCTINTERP_API void delete_elements (const octave_value_list& idx);
 
--- a/libinterp/operators/op-scm-cm.cc	Thu Jul 01 15:28:17 2021 +0200
+++ b/libinterp/operators/op-scm-cm.cc	Wed Jun 30 17:52:03 2021 -0400
@@ -31,6 +31,7 @@
 #include "ov.h"
 #include "ov-typeinfo.h"
 #include "ov-cx-mat.h"
+#include "ov-flt-cx-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 
@@ -138,17 +139,8 @@
          (v1.sparse_complex_matrix_value ().concat (tmp, ra_idx));
 }
 
-DEFASSIGNOP (assign, sparse_complex_matrix, complex_matrix)
-{
-  octave_sparse_complex_matrix& v1
-    = dynamic_cast<octave_sparse_complex_matrix&> (a1);
-  const octave_complex_matrix& v2
-    = dynamic_cast<const octave_complex_matrix&> (a2);
-
-  SparseComplexMatrix tmp (v2.complex_matrix_value ());
-  v1.assign (idx, tmp);
-  return octave_value ();
-}
+DEFNDASSIGNOP_FN (assign, sparse_complex_matrix, complex_matrix, complex_matrix, assign);
+DEFNDASSIGNOP_FN (sgl_assign, sparse_complex_matrix, float_complex_matrix, complex_matrix, assign);
 
 void
 install_scm_cm_ops (octave::type_info& ti)
@@ -199,4 +191,6 @@
 
   INSTALL_ASSIGNOP_TI (ti, op_asn_eq, octave_sparse_complex_matrix,
                        octave_complex_matrix, assign);
+  INSTALL_ASSIGNOP_TI (ti, op_asn_eq, octave_sparse_complex_matrix,
+                       octave_float_complex_matrix, sgl_assign);
 }
--- a/libinterp/operators/op-scm-cs.cc	Thu Jul 01 15:28:17 2021 +0200
+++ b/libinterp/operators/op-scm-cs.cc	Wed Jun 30 17:52:03 2021 -0400
@@ -32,6 +32,7 @@
 #include "ov-typeinfo.h"
 #include "ov-cx-mat.h"
 #include "ov-complex.h"
+#include "ov-flt-complex.h"
 #include "ops.h"
 #include "xpow.h"
 
@@ -125,16 +126,8 @@
          (v1.sparse_complex_matrix_value ().concat (tmp, ra_idx));
 }
 
-DEFASSIGNOP (assign, sparse_complex_matrix, complex)
-{
-  octave_sparse_complex_matrix& v1
-    = dynamic_cast<octave_sparse_complex_matrix&> (a1);
-  const octave_complex& v2 = dynamic_cast<const octave_complex&> (a2);
-
-  SparseComplexMatrix tmp (1, 1, v2.complex_value ());
-  v1.assign (idx, tmp);
-  return octave_value ();
-}
+DEFNDASSIGNOP_FN (assign, sparse_complex_matrix, complex, complex, assign);
+DEFNDASSIGNOP_FN (sgl_assign, sparse_complex_matrix, float_complex, complex, assign);
 
 void
 install_scm_cs_ops (octave::type_info& ti)
@@ -173,6 +166,7 @@
   INSTALL_CATOP_TI (ti, octave_sparse_complex_matrix, octave_complex, scm_cs);
 
   INSTALL_ASSIGNOP_TI (ti, op_asn_eq, octave_sparse_complex_matrix,
-                       octave_complex,
-                       assign);
+                       octave_complex, assign);
+  INSTALL_ASSIGNOP_TI (ti, op_asn_eq, octave_sparse_complex_matrix,
+                       octave_float_complex, sgl_assign);
 }
--- a/libinterp/operators/op-scm-m.cc	Thu Jul 01 15:28:17 2021 +0200
+++ b/libinterp/operators/op-scm-m.cc	Wed Jun 30 17:52:03 2021 -0400
@@ -31,6 +31,7 @@
 #include "ov.h"
 #include "ov-typeinfo.h"
 #include "ov-re-mat.h"
+#include "ov-flt-re-mat.h"
 #include "ov-cx-mat.h"
 #include "ops.h"
 #include "xdiv.h"
@@ -131,16 +132,8 @@
          (v1.sparse_complex_matrix_value ().concat (tmp, ra_idx));
 }
 
-DEFASSIGNOP (assign, sparse_complex_matrix, matrix)
-{
-  octave_sparse_complex_matrix& v1
-    = dynamic_cast<octave_sparse_complex_matrix&> (a1);
-  const octave_matrix& v2 = dynamic_cast<const octave_matrix&> (a2);
-
-  SparseComplexMatrix tmp (v2.complex_matrix_value ());
-  v1.assign (idx, tmp);
-  return octave_value ();
-}
+DEFNDASSIGNOP_FN (assign, sparse_complex_matrix, matrix, complex_matrix, assign);
+DEFNDASSIGNOP_FN (sgl_assign, sparse_complex_matrix, float_matrix, complex_matrix, assign);
 
 void
 install_scm_m_ops (octave::type_info& ti)
@@ -175,4 +168,6 @@
 
   INSTALL_ASSIGNOP_TI (ti, op_asn_eq, octave_sparse_complex_matrix, octave_matrix,
                        assign);
+  INSTALL_ASSIGNOP_TI (ti, op_asn_eq, octave_sparse_complex_matrix, octave_float_matrix,
+                       sgl_assign);
 }
--- a/libinterp/operators/op-scm-s.cc	Thu Jul 01 15:28:17 2021 +0200
+++ b/libinterp/operators/op-scm-s.cc	Wed Jun 30 17:52:03 2021 -0400
@@ -32,6 +32,7 @@
 #include "ov-typeinfo.h"
 #include "ov-cx-mat.h"
 #include "ov-scalar.h"
+#include "ov-float.h"
 #include "ops.h"
 #include "xpow.h"
 
@@ -133,16 +134,8 @@
          (v1.sparse_complex_matrix_value ().concat (tmp, ra_idx));
 }
 
-DEFASSIGNOP (assign, sparse_complex_matrix, scalar)
-{
-  octave_sparse_complex_matrix& v1
-    = dynamic_cast<octave_sparse_complex_matrix&> (a1);
-  const octave_scalar& v2 = dynamic_cast<const octave_scalar&> (a2);
-
-  SparseComplexMatrix tmp (1, 1, v2.complex_value ());
-  v1.assign (idx, tmp);
-  return octave_value ();
-}
+DEFNDASSIGNOP_FN (assign, sparse_complex_matrix, scalar, scalar, assign);
+DEFNDASSIGNOP_FN (sgl_assign, sparse_complex_matrix, float_scalar, scalar, assign);
 
 void
 install_scm_s_ops (octave::type_info& ti)
@@ -177,4 +170,6 @@
 
   INSTALL_ASSIGNOP_TI (ti, op_asn_eq, octave_sparse_complex_matrix, octave_scalar,
                        assign);
+  INSTALL_ASSIGNOP_TI (ti, op_asn_eq, octave_sparse_complex_matrix, octave_float_scalar,
+                       sgl_assign);
 }
--- a/libinterp/operators/op-sm-cm.cc	Thu Jul 01 15:28:17 2021 +0200
+++ b/libinterp/operators/op-sm-cm.cc	Wed Jun 30 17:52:03 2021 -0400
@@ -31,6 +31,7 @@
 #include "ov.h"
 #include "ov-typeinfo.h"
 #include "ov-cx-mat.h"
+#include "ov-flt-cx-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 
@@ -174,6 +175,9 @@
   INSTALL_ASSIGNCONV_TI (ti, octave_sparse_matrix, octave_complex_matrix,
                          octave_sparse_complex_matrix);
 
+  INSTALL_ASSIGNCONV_TI (ti, octave_sparse_matrix, octave_float_complex_matrix,
+                         octave_sparse_complex_matrix);
+
   INSTALL_WIDENOP_TI (ti, octave_sparse_matrix, octave_complex_matrix,
                       sparse_complex_matrix_conv);
 }
--- a/libinterp/operators/op-sm-cs.cc	Thu Jul 01 15:28:17 2021 +0200
+++ b/libinterp/operators/op-sm-cs.cc	Wed Jun 30 17:52:03 2021 -0400
@@ -31,6 +31,7 @@
 #include "ov.h"
 #include "ov-typeinfo.h"
 #include "ov-complex.h"
+#include "ov-flt-complex.h"
 #include "ops.h"
 #include "xpow.h"
 
@@ -148,4 +149,7 @@
 
   INSTALL_ASSIGNCONV_TI (ti, octave_sparse_matrix, octave_complex,
                          octave_sparse_complex_matrix);
+
+  INSTALL_ASSIGNCONV_TI (ti, octave_sparse_matrix, octave_float_complex,
+                         octave_sparse_complex_matrix);
 }
--- a/libinterp/operators/op-sm-m.cc	Thu Jul 01 15:28:17 2021 +0200
+++ b/libinterp/operators/op-sm-m.cc	Wed Jun 30 17:52:03 2021 -0400
@@ -31,6 +31,7 @@
 #include "ov.h"
 #include "ov-typeinfo.h"
 #include "ov-re-mat.h"
+#include "ov-flt-re-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 
@@ -124,15 +125,8 @@
   return octave_value (v1.sparse_matrix_value (). concat (tmp, ra_idx));
 }
 
-DEFASSIGNOP (assign, sparse_matrix, matrix)
-{
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
-  const octave_matrix& v2 = dynamic_cast<const octave_matrix&> (a2);
-
-  SparseMatrix tmp (v2.matrix_value ());
-  v1.assign (idx, tmp);
-  return octave_value ();
-}
+DEFNDASSIGNOP_FN (assign, sparse_matrix, matrix, matrix, assign);
+DEFNDASSIGNOP_FN (sgl_assign, sparse_matrix, float_matrix, matrix, assign);
 
 void
 install_sm_m_ops (octave::type_info& ti)
@@ -164,4 +158,6 @@
 
   INSTALL_ASSIGNOP_TI (ti, op_asn_eq, octave_sparse_matrix, octave_matrix,
                        assign);
+  INSTALL_ASSIGNOP_TI (ti, op_asn_eq, octave_sparse_matrix, octave_float_matrix,
+                       sgl_assign);
 }
--- a/libinterp/operators/op-sm-s.cc	Thu Jul 01 15:28:17 2021 +0200
+++ b/libinterp/operators/op-sm-s.cc	Wed Jun 30 17:52:03 2021 -0400
@@ -31,6 +31,7 @@
 #include "ov.h"
 #include "ov-typeinfo.h"
 #include "ov-scalar.h"
+#include "ov-float.h"
 #include "ops.h"
 #include "xpow.h"
 
@@ -121,15 +122,8 @@
   return octave_value (v1.sparse_matrix_value (). concat (tmp, ra_idx));
 }
 
-DEFASSIGNOP (assign, sparse_matrix, scalar)
-{
-  octave_sparse_matrix& v1 = dynamic_cast<octave_sparse_matrix&> (a1);
-  const octave_scalar& v2 = dynamic_cast<const octave_scalar&> (a2);
-
-  SparseMatrix tmp (1, 1, v2.scalar_value ());
-  v1.assign (idx, tmp);
-  return octave_value ();
-}
+DEFNDASSIGNOP_FN (assign, sparse_matrix, scalar, scalar, assign);
+DEFNDASSIGNOP_FN (sgl_assign, sparse_matrix, float_scalar, scalar, assign);
 
 void
 install_sm_s_ops (octave::type_info& ti)
@@ -158,4 +152,6 @@
 
   INSTALL_ASSIGNOP_TI (ti, op_asn_eq, octave_sparse_matrix, octave_scalar,
                        assign);
+  INSTALL_ASSIGNOP_TI (ti, op_asn_eq, octave_sparse_matrix, octave_float_scalar,
+                       sgl_assign);
 }
--- a/liboctave/array/Sparse.cc	Thu Jul 01 15:28:17 2021 +0200
+++ b/liboctave/array/Sparse.cc	Wed Jun 30 17:52:03 2021 -0400
@@ -2020,6 +2020,18 @@
 template <typename T>
 OCTAVE_API
 void
+Sparse<T>::assign (const octave::idx_vector& idx, const T& rhs)
+{
+  // FIXME: Converting the RHS and forwarding to the sparse matrix
+  // assignment function is simpler, but it might be good to have a
+  // specialization...
+
+  assign (idx, Sparse<T> (1, 1, rhs));
+}
+
+template <typename T>
+OCTAVE_API
+void
 Sparse<T>::assign (const octave::idx_vector& idx_i,
                    const octave::idx_vector& idx_j, const Sparse<T>& rhs)
 {
@@ -2255,6 +2267,19 @@
     octave::err_nonconformant  ("=", idx_i.length (nr), idx_j.length (nc), n, m);
 }
 
+template <typename T>
+OCTAVE_API
+void
+Sparse<T>::assign (const octave::idx_vector& idx_i,
+                   const octave::idx_vector& idx_j, const T& rhs)
+{
+  // FIXME: Converting the RHS and forwarding to the sparse matrix
+  // assignment function is simpler, but it might be good to have a
+  // specialization...
+
+  assign (idx_i, idx_j, Sparse<T> (1, 1, rhs));
+}
+
 // Can't use versions of these in Array.cc due to duplication of the
 // instantiations for Array<double and Sparse<double>, etc
 template <typename T>
--- a/liboctave/array/Sparse.h	Thu Jul 01 15:28:17 2021 +0200
+++ b/liboctave/array/Sparse.h	Wed Jun 30 17:52:03 2021 -0400
@@ -525,10 +525,15 @@
 
   OCTAVE_API void assign (const octave::idx_vector& i, const Sparse<T>& rhs);
 
+  OCTAVE_API void assign (const octave::idx_vector& i, const T& rhs);
+
   OCTAVE_API void
   assign (const octave::idx_vector& i, const octave::idx_vector& j, const Sparse<T>& rhs);
 
   OCTAVE_API void
+  assign (const octave::idx_vector& i, const octave::idx_vector& j, const T& rhs);
+
+  OCTAVE_API void
   print_info (std::ostream& os, const std::string& prefix) const;
 
   // Unsafe.  These functions exist to support the MEX interface.
--- a/test/module.mk	Thu Jul 01 15:28:17 2021 +0200
+++ b/test/module.mk	Wed Jun 30 17:52:03 2021 -0400
@@ -48,6 +48,7 @@
   %reldir%/return.tst \
   %reldir%/single-index.tst \
   %reldir%/slice.tst \
+  %reldir%/sparse-assign.tst \
   %reldir%/struct.tst \
   %reldir%/switch.tst \
   %reldir%/system.tst \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sparse-assign.tst	Wed Jun 30 17:52:03 2021 -0400
@@ -0,0 +1,328 @@
+########################################################################
+##
+## Copyright (C) 2021 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## FIXME: will also need tests for if assignment of integer values
+## once that is implemented.  The pattern can be the same.
+
+%!shared lr, lc, rr, rc, si, sj, mi, mj, sm_lhs, csm_lhs, s, m, sm, cs, cm, csm
+%! lr = 6;
+%! lc = 8;
+%! rr = 2;
+%! rc = 3;
+%! si = 2;
+%! sj = 3;
+%! mi = (1:rr)+2;
+%! mj = (1:rc)+3;
+%! sm_lhs = sprand (lr, lc, 0.1);
+%! csm_lhs = sm_lhs + 1i * sprand (lr, lc, 0.1);
+%! s = rand ();
+%! m = rand (rr, rc);
+%! sm = sprand (rr, rc, 0.1);
+%! cs = s + 1i * rand ();
+%! cm = m + 1i * rand (rr, rc);
+%! csm = cm + 1i * sprand (rr, rc, 0.1);
+
+%% Indexed assignment of double scalar, sparse with a single element,
+%% complex scalar, and sparse complex with a single element to sparse matrix.
+
+%!test
+%! lhs = sm_lhs;
+%! rhs = s;
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(si,sj) = rhs;
+%! flhs(si,sj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = sm_lhs;
+%! rhs = sparse (s);
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(si,sj) = rhs;
+%! flhs(si,sj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = sm_lhs;
+%! rhs = cs;
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(si,sj) = rhs;
+%! flhs(si,sj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = sm_lhs;
+%! rhs = sparse (cs);
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(si,sj) = rhs;
+%! flhs(si,sj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%% Indexed assignment of double scalar, sparse with a single element,
+%% complex scalar, and sparse complex with a single element to complex
+%% sparse matrix.
+
+%!test
+%! lhs = csm_lhs;
+%! rhs = s;
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(si,sj) = rhs;
+%! flhs(si,sj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = csm_lhs;
+%! rhs = sparse (s);
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(si,sj) = rhs;
+%! flhs(si,sj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = csm_lhs;
+%! rhs = cs;
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(si,sj) = rhs;
+%! flhs(si,sj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = csm_lhs;
+%! rhs = sparse (cs);
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(si,sj) = rhs;
+%! flhs(si,sj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%% Indexed assignment of matrix, sparse matrix, complex matrix,
+%% and complex sparse matrix to sparse matrix.
+
+%!test
+%! lhs = sm_lhs;
+%! rhs = m;
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(mi,mj) = rhs;
+%! flhs(mi,mj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = sm_lhs;
+%! rhs = sm;
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(mi,mj) = rhs;
+%! flhs(mi,mj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = sm_lhs;
+%! rhs = cm;
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(mi,mj) = rhs;
+%! flhs(mi,mj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = sm_lhs;
+%! rhs = csm;
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(mi,mj) = rhs;
+%! flhs(mi,mj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%% Indexed assignment of matrix, sparse matrix, complex matrix,
+%% and complex sparse matrix to complex sparse matrix.
+
+%!test
+%! lhs = csm_lhs;
+%! rhs = m;
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(mi,mj) = rhs;
+%! flhs(mi,mj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = csm_lhs;
+%! rhs = sm;
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(mi,mj) = rhs;
+%! flhs(mi,mj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = csm_lhs;
+%! rhs = cm;
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(mi,mj) = rhs;
+%! flhs(mi,mj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = csm_lhs;
+%! rhs = csm;
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(mi,mj) = rhs;
+%! flhs(mi,mj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%% Indexed assignment of float scalar, float complex scalar, float matrix,
+%% and float complex matrix to sparse matrix.
+
+%!test
+%! lhs = sm_lhs;
+%! rhs = single (s);
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(si,sj) = rhs;
+%! flhs(si,sj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = sm_lhs;
+%! rhs = single (cs);
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(si,sj) = rhs;
+%! flhs(si,sj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = sm_lhs;
+%! rhs = single (m);
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(mi,mj) = rhs;
+%! flhs(mi,mj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = sm_lhs;
+%! rhs = single (cm);
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(mi,mj) = rhs;
+%! flhs(mi,mj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%% Indexed assignment of float scalar, float complex scalar, float matrix,
+%% and float complex matrix to complex sparse matrix.
+
+%!test
+%! lhs = csm_lhs;
+%! rhs = single (s);
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(si,sj) = rhs;
+%! flhs(si,sj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = csm_lhs;
+%! rhs = single (cs);
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(si,sj) = rhs;
+%! flhs(si,sj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = csm_lhs;
+%! rhs = single (m);
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(mi,mj) = rhs;
+%! flhs(mi,mj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));
+
+%!test
+%! lhs = csm_lhs;
+%! rhs = single (cm);
+%! flhs = full (lhs);
+%! frhs = full (rhs);
+%! lhs(mi,mj) = rhs;
+%! flhs(mi,mj) = frhs;
+%! assert (issparse (lhs));
+%! assert (full (lhs), flhs);
+%! assert (iscomplex (lhs), iscomplex (lhs) || iscomplex (rhs));