@@ -25,6 +25,9 @@ import sage.modules.free_module
2525from sage.structure.coerce cimport coercion_model
2626
2727
28+ _MISSING = object ()
29+
30+
2831cdef class Matrix(Matrix0):
2932 # ##################################################
3033 # Coercion to Various Systems
@@ -670,7 +673,7 @@ cdef class Matrix(Matrix0):
670673 entries = [[sib(v, 2 ) for v in row] for row in self .rows()]
671674 return sib.name(' matrix' )(self .base_ring(), entries)
672675
673- def numpy (self , dtype = None , copy = True ):
676+ def numpy (self , dtype = None , copy = _MISSING ):
674677 """
675678 Return the Numpy matrix associated to this matrix.
676679
@@ -680,14 +683,6 @@ cdef class Matrix(Matrix0):
680683 then the type will be determined as the minimum type required
681684 to hold the objects in the sequence.
682685
683- - ``copy`` -- if `self` is already an `ndarray`, then this flag
684- determines whether the data is copied (the default), or whether
685- the internal array is returned. Note that this is incompatible
686- with the behavior of ``copy`` argument to ``__array__`` method
687- in numpy 2.0, see `Adapting to changes in the copy keyword
688- <https://numpy.org/devdocs/numpy_2_0_migration_guide.html#adapting-to-changes-in-the-copy-keyword>`_.
689- Currently SageMath is using numpy 1.26.
690-
691686 EXAMPLES::
692687
693688 sage: # needs numpy
@@ -713,7 +708,7 @@ cdef class Matrix(Matrix0):
713708 typecodes::
714709
715710 sage: import numpy # needs numpy
716- sage: numpy.typecodes.items() # needs numpy
711+ sage: numpy.typecodes.items() # needs numpy # random
717712 [('All', '?bhilqpBHILQPefdgFDGSUVOMm'), ('AllFloat', 'efdgFDG'),
718713 ...
719714
@@ -738,40 +733,69 @@ cdef class Matrix(Matrix0):
738733 sage: b.shape
739734 (3, 4)
740735
741- TESTS:
742-
743- This ensures the docstring above is correct. It needs to be changed
744- when numpy version in SageMath is updated to 2.0.0::
736+ TESTS::
745737
746738 sage: # needs numpy
747- sage: import numpy as np
748- sage: np.__version__
749- '1.26.4'
739+ sage: matrix(3, range(12)).numpy(copy=False)
740+ doctest:warning...
741+ DeprecationWarning: passing copy argument to numpy() is deprecated
742+ See https://github.com/sagemath/sage/issues/39152 for details.
743+ array([[ 0, 1, 2, 3],
744+ [ 4, 5, 6, 7],
745+ [ 8, 9, 10, 11]])
750746 """
747+ if copy is not _MISSING:
748+ from sage.misc.superseded import deprecation
749+ deprecation(39152 , " passing copy argument to numpy() is deprecated" )
751750 import numpy
752751 return numpy.asarray(self .list(), dtype = dtype).reshape(self .nrows(), self .ncols())
753752
754- def __array__ (self , dtype = None ):
753+ def __array__ (self , dtype = None , copy = None ):
755754 """
756755 Define the magic ``__array__`` function so that ``numpy.array(m)`` can convert
757756 a matrix ``m`` to a numpy array. See
758757 `Interoperability with NumPy <https://numpy.org/doc/1.26/user/basics.interoperability.html>`_.
759758
760759 Note that subclasses should override :meth:`numpy`, but usually not this method.
761760
762- SageMath is using Numpy 1.26, so there is no ``copy`` argument.
761+ INPUT:
763762
764- TESTS:
763+ - ``dtype`` -- the desired data-type for the array. If not given,
764+ then the type will be determined automatically.
765765
766- This ensures the docstring above is correct. It needs to be changed
767- when numpy version in SageMath is updated to 2.0.0::
766+ - ``copy`` -- required for numpy 2.0 compatibility.
767+ See <https://numpy.org/devdocs/numpy_2_0_migration_guide.html#adapting-to-changes-in-the-copy-keyword>`_.
768+ Note that ``copy=False`` is not supported.
769+
770+ TESTS::
768771
769772 sage: # needs numpy
770773 sage: import numpy as np
771- sage: np.__version__
772- '1.26.4'
773- """
774- return self .numpy(dtype, copy = False )
774+ sage: a = matrix(3, range(12))
775+ sage: if np.lib.NumpyVersion(np.__version__) >= '2.0.0':
776+ ....: try:
777+ ....: np.array(a, copy=False) # in numpy 2.0, this raises an error
778+ ....: except ValueError:
779+ ....: pass
780+ ....: else:
781+ ....: assert False
782+ ....: else:
783+ ....: b = np.array(a, copy=False) # in numpy 1.26, this means "avoid copy if possible"
784+ ....: # https://numpy.org/doc/1.26/reference/generated/numpy.array.html#numpy.array
785+ ....: # but no-copy is not supported so it will copy anyway
786+ ....: a[0,0] = 1
787+ ....: assert b[0,0] == 0
788+ ....: b = np.asarray(a)
789+ ....: a[0,0] = 2
790+ ....: assert b[0,0] == 1
791+ """
792+ import numpy as np
793+ if np.lib.NumpyVersion(np.__version__) >= ' 2.0.0' :
794+ if copy is False :
795+ raise ValueError (" Sage matrix cannot be converted to numpy array without copying" )
796+ else :
797+ assert copy is None # numpy versions before 2.0 should not pass copy argument
798+ return self .numpy(dtype)
775799
776800 # ##################################################
777801 # Construction functions
0 commit comments