-
-
Notifications
You must be signed in to change notification settings - Fork 491
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Trac #19240: Rename matrix_mod2e_dense to matrix_gf2e_dense
The name `matrix_mod2e_dense` suggests that it's about matrices in `ZZ/(2^e)ZZ`, while it's really for matrices in `GF(2^e)`. Since the module and class names are non-public implementation details, there is no need for deprecation. URL: http://trac.sagemath.org/19240 Reported by: jdemeyer Ticket author(s): Jeroen Demeyer Reviewer(s): Simon King
- Loading branch information
Showing
6 changed files
with
81 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from sage.libs.m4rie cimport mzed_t | ||
|
||
cimport matrix_dense | ||
|
||
cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): | ||
cdef mzed_t *_entries | ||
cdef object _one | ||
cdef object _zero | ||
|
||
cpdef Matrix_gf2e_dense _multiply_newton_john(Matrix_gf2e_dense self, Matrix_gf2e_dense right) | ||
cpdef Matrix_gf2e_dense _multiply_karatsuba(Matrix_gf2e_dense self, Matrix_gf2e_dense right) | ||
cpdef Matrix_gf2e_dense _multiply_strassen(Matrix_gf2e_dense self, Matrix_gf2e_dense right, cutoff=*) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ The M4RIE library offers two matrix representations: | |
words such that each element is filled with zeroes until the next | ||
power of two. Thus, for example, elements of `\GF{2^3}` are | ||
represented as ``[0xxx|0xxx|0xxx|0xxx|...]``. This representation is | ||
wrapped as :class:`Matrix_mod2e_dense` in Sage. | ||
wrapped as :class:`Matrix_gf2e_dense` in Sage. | ||
Multiplication and elimination both use "Newton-John" tables. These | ||
tables are simply all possible multiples of a given row in a matrix | ||
|
@@ -50,7 +50,7 @@ AUTHOR: | |
TESTS:: | ||
sage: TestSuite(sage.matrix.matrix_mod2e_dense.Matrix_mod2e_dense).run(verbose=True) | ||
sage: TestSuite(sage.matrix.matrix_gf2e_dense.Matrix_gf2e_dense).run(verbose=True) | ||
running ._test_pickling() . . . pass | ||
TODO: | ||
|
@@ -66,6 +66,16 @@ REFERENCES: | |
http://arxiv.org/abs/0901.1413 | ||
""" | ||
|
||
#***************************************************************************** | ||
# Copyright (C) 2010 Martin Albrecht <[email protected]> | ||
# | ||
# This program 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 2 of the License, or | ||
# (at your option) any later version. | ||
# http://www.gnu.org/licenses/ | ||
#***************************************************************************** | ||
|
||
include "sage/ext/interrupt.pxi" | ||
|
||
cimport matrix_dense | ||
|
@@ -100,17 +110,17 @@ cdef class M4RIE_finite_field: | |
""" | ||
EXAMPLE:: | ||
sage: from sage.matrix.matrix_mod2e_dense import M4RIE_finite_field | ||
sage: from sage.matrix.matrix_gf2e_dense import M4RIE_finite_field | ||
sage: K = M4RIE_finite_field(); K | ||
<sage.matrix.matrix_mod2e_dense.M4RIE_finite_field object at 0x...> | ||
<sage.matrix.matrix_gf2e_dense.M4RIE_finite_field object at 0x...> | ||
""" | ||
pass | ||
|
||
def __dealloc__(self): | ||
""" | ||
EXAMPLE:: | ||
sage: from sage.matrix.matrix_mod2e_dense import M4RIE_finite_field | ||
sage: from sage.matrix.matrix_gf2e_dense import M4RIE_finite_field | ||
sage: K = M4RIE_finite_field() | ||
sage: del K | ||
""" | ||
|
@@ -123,7 +133,7 @@ cdef m4ri_word poly_to_word(f): | |
cdef object word_to_poly(w, F): | ||
return F.fetch_int(w) | ||
|
||
cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | ||
cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): | ||
######################################################################## | ||
# LEVEL 1 functionality | ||
######################################################################## | ||
|
@@ -336,19 +346,19 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
[a^3 + a^2 + 1 a^3 + a^2 + a a^3 + a^2 + a a^3 + 1] | ||
[a^3 + a^2 + 1 a^3 + a^2 a^3 + a^2 a^2] | ||
""" | ||
cdef Matrix_mod2e_dense A | ||
A = Matrix_mod2e_dense.__new__(Matrix_mod2e_dense, self._parent, 0, 0, 0, alloc=False) | ||
cdef Matrix_gf2e_dense A | ||
A = Matrix_gf2e_dense.__new__(Matrix_gf2e_dense, self._parent, 0, 0, 0, alloc=False) | ||
if self._nrows == 0 or self._ncols == 0: | ||
return A | ||
A._entries = mzed_add(NULL, self._entries, (<Matrix_mod2e_dense>right)._entries) | ||
A._entries = mzed_add(NULL, self._entries, (<Matrix_gf2e_dense>right)._entries) | ||
|
||
return A | ||
|
||
cpdef ModuleElement _sub_(self, ModuleElement right): | ||
""" | ||
EXAMPLE:: | ||
sage: from sage.matrix.matrix_mod2e_dense import Matrix_mod2e_dense | ||
sage: from sage.matrix.matrix_gf2e_dense import Matrix_gf2e_dense | ||
sage: K.<a> = GF(2^4) | ||
sage: m,n = 3, 4 | ||
sage: MS = MatrixSpace(K,m,n) | ||
|
@@ -406,13 +416,13 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
if self._ncols != right._nrows: | ||
raise ArithmeticError("left ncols must match right nrows") | ||
|
||
cdef Matrix_mod2e_dense ans | ||
cdef Matrix_gf2e_dense ans | ||
|
||
ans = self.new_matrix(nrows = self.nrows(), ncols = right.ncols()) | ||
if self._nrows == 0 or self._ncols == 0 or right._ncols == 0: | ||
return ans | ||
sig_on() | ||
ans._entries = mzed_mul_naive(ans._entries, self._entries, (<Matrix_mod2e_dense>right)._entries) | ||
ans._entries = mzed_mul_naive(ans._entries, self._entries, (<Matrix_gf2e_dense>right)._entries) | ||
sig_off() | ||
return ans | ||
|
||
|
@@ -449,17 +459,17 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
if self._ncols != right._nrows: | ||
raise ArithmeticError("left ncols must match right nrows") | ||
|
||
cdef Matrix_mod2e_dense ans | ||
cdef Matrix_gf2e_dense ans | ||
|
||
ans = self.new_matrix(nrows = self.nrows(), ncols = right.ncols()) | ||
if self._nrows == 0 or self._ncols == 0 or right._ncols == 0: | ||
return ans | ||
sig_on() | ||
ans._entries = mzed_mul(ans._entries, self._entries, (<Matrix_mod2e_dense>right)._entries) | ||
ans._entries = mzed_mul(ans._entries, self._entries, (<Matrix_gf2e_dense>right)._entries) | ||
sig_off() | ||
return ans | ||
|
||
cpdef Matrix_mod2e_dense _multiply_newton_john(Matrix_mod2e_dense self, Matrix_mod2e_dense right): | ||
cpdef Matrix_gf2e_dense _multiply_newton_john(Matrix_gf2e_dense self, Matrix_gf2e_dense right): | ||
""" | ||
Return A*B using Newton-John tables. | ||
|
@@ -510,18 +520,18 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
if self._ncols != right._nrows: | ||
raise ArithmeticError("left ncols must match right nrows") | ||
|
||
cdef Matrix_mod2e_dense ans | ||
cdef Matrix_gf2e_dense ans | ||
|
||
ans = self.new_matrix(nrows = self.nrows(), ncols = right.ncols()) | ||
if self._nrows == 0 or self._ncols == 0 or right._ncols == 0: | ||
return ans | ||
|
||
sig_on() | ||
ans._entries = mzed_mul_newton_john(ans._entries, self._entries, (<Matrix_mod2e_dense>right)._entries) | ||
ans._entries = mzed_mul_newton_john(ans._entries, self._entries, (<Matrix_gf2e_dense>right)._entries) | ||
sig_off() | ||
return ans | ||
|
||
cpdef Matrix_mod2e_dense _multiply_karatsuba(Matrix_mod2e_dense self, Matrix_mod2e_dense right): | ||
cpdef Matrix_gf2e_dense _multiply_karatsuba(Matrix_gf2e_dense self, Matrix_gf2e_dense right): | ||
""" | ||
Matrix multiplication using Karatsuba over polynomials with | ||
matrix coefficients over GF(2). | ||
|
@@ -558,18 +568,18 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
if self._ncols != right._nrows: | ||
raise ArithmeticError("left ncols must match right nrows") | ||
|
||
cdef Matrix_mod2e_dense ans | ||
cdef Matrix_gf2e_dense ans | ||
|
||
ans = self.new_matrix(nrows = self.nrows(), ncols = right.ncols()) | ||
if self._nrows == 0 or self._ncols == 0 or right._ncols == 0: | ||
return ans | ||
|
||
sig_on() | ||
ans._entries = mzed_mul_karatsuba(ans._entries, self._entries, (<Matrix_mod2e_dense>right)._entries) | ||
ans._entries = mzed_mul_karatsuba(ans._entries, self._entries, (<Matrix_gf2e_dense>right)._entries) | ||
sig_off() | ||
return ans | ||
|
||
cpdef Matrix_mod2e_dense _multiply_strassen(Matrix_mod2e_dense self, Matrix_mod2e_dense right, cutoff=0): | ||
cpdef Matrix_gf2e_dense _multiply_strassen(Matrix_gf2e_dense self, Matrix_gf2e_dense right, cutoff=0): | ||
""" | ||
Winograd-Strassen matrix multiplication with Newton-John | ||
multiplication as base case. | ||
|
@@ -609,17 +619,17 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
if self._ncols != right._nrows: | ||
raise ArithmeticError("left ncols must match right nrows") | ||
|
||
cdef Matrix_mod2e_dense ans | ||
cdef Matrix_gf2e_dense ans | ||
|
||
ans = self.new_matrix(nrows = self.nrows(), ncols = right.ncols()) | ||
if self._nrows == 0 or self._ncols == 0 or right._ncols == 0: | ||
return ans | ||
|
||
if cutoff == 0: | ||
cutoff = _mzed_strassen_cutoff(ans._entries, self._entries, (<Matrix_mod2e_dense>right)._entries) | ||
cutoff = _mzed_strassen_cutoff(ans._entries, self._entries, (<Matrix_gf2e_dense>right)._entries) | ||
|
||
sig_on() | ||
ans._entries = mzed_mul_strassen(ans._entries, self._entries, (<Matrix_mod2e_dense>right)._entries, cutoff) | ||
ans._entries = mzed_mul_strassen(ans._entries, self._entries, (<Matrix_gf2e_dense>right)._entries, cutoff) | ||
sig_off() | ||
return ans | ||
|
||
|
@@ -660,7 +670,7 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
[ a 1 0 a a + 1 0 0 a + 1 1 a + 1] | ||
""" | ||
cdef m4ri_word a = poly_to_word(right) | ||
cdef Matrix_mod2e_dense C = Matrix_mod2e_dense.__new__(Matrix_mod2e_dense, self._parent, 0, 0, 0) | ||
cdef Matrix_gf2e_dense C = Matrix_gf2e_dense.__new__(Matrix_gf2e_dense, self._parent, 0, 0, 0) | ||
mzed_mul_scalar(C._entries, a, self._entries) | ||
return C | ||
|
||
|
@@ -696,7 +706,7 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
""" | ||
if self._nrows == 0 or self._ncols == 0: | ||
return 0 | ||
return mzed_cmp(self._entries, (<Matrix_mod2e_dense>right)._entries) | ||
return mzed_cmp(self._entries, (<Matrix_gf2e_dense>right)._entries) | ||
|
||
def __copy__(self): | ||
""" | ||
|
@@ -718,8 +728,8 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
sage: A2[0,0] | ||
a^2 | ||
""" | ||
cdef Matrix_mod2e_dense A | ||
A = Matrix_mod2e_dense.__new__(Matrix_mod2e_dense, self._parent, 0, 0, 0) | ||
cdef Matrix_gf2e_dense A | ||
A = Matrix_gf2e_dense.__new__(Matrix_gf2e_dense, self._parent, 0, 0, 0) | ||
|
||
if self._nrows and self._ncols: | ||
mzed_copy(A._entries, <const_mzed_t *>self._entries) | ||
|
@@ -997,8 +1007,8 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
[0 1 0] | ||
[0 0 1] | ||
""" | ||
cdef Matrix_mod2e_dense A | ||
A = Matrix_mod2e_dense.__new__(Matrix_mod2e_dense, self._parent, 0, 0, 0) | ||
cdef Matrix_gf2e_dense A | ||
A = Matrix_gf2e_dense.__new__(Matrix_gf2e_dense, self._parent, 0, 0, 0) | ||
|
||
if self._nrows and self._nrows == self._ncols: | ||
mzed_invert_newton_john(A._entries, self._entries) | ||
|
@@ -1132,7 +1142,7 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
""" | ||
mzed_col_swap(self._entries, col1, col2) | ||
|
||
def augment(self, Matrix_mod2e_dense right): | ||
def augment(self, Matrix_gf2e_dense right): | ||
""" | ||
Augments ``self`` with ``right``. | ||
|
@@ -1190,10 +1200,10 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
sage: M.augment(N) | ||
[] | ||
""" | ||
cdef Matrix_mod2e_dense A | ||
cdef Matrix_gf2e_dense A | ||
|
||
if self._nrows != right._nrows: | ||
raise TypeError, "Both numbers of rows must match." | ||
raise TypeError("Both numbers of rows must match.") | ||
|
||
if self._ncols == 0: | ||
return right.__copy__() | ||
|
@@ -1206,7 +1216,7 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
A._entries = mzed_concat(A._entries, self._entries, right._entries) | ||
return A | ||
|
||
def stack(self, Matrix_mod2e_dense other): | ||
def stack(self, Matrix_gf2e_dense other): | ||
""" | ||
Stack ``self`` on top of ``other``. | ||
|
@@ -1262,14 +1272,14 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
[] | ||
""" | ||
if self._ncols != other._ncols: | ||
raise TypeError, "Both numbers of columns must match." | ||
raise TypeError("Both numbers of columns must match.") | ||
|
||
if self._nrows == 0: | ||
return other.__copy__() | ||
if other._nrows == 0: | ||
return self.__copy__() | ||
|
||
cdef Matrix_mod2e_dense A | ||
cdef Matrix_gf2e_dense A | ||
A = self.new_matrix(nrows = self._nrows + other._nrows) | ||
if self._ncols == 0: | ||
return A | ||
|
@@ -1335,7 +1345,7 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
if highr > self._entries.nrows: | ||
raise TypeError("Expected highr <= self.nrows(), but got %d > %d instead."%(highr, self._entries.nrows)) | ||
|
||
cdef Matrix_mod2e_dense A = self.new_matrix(nrows = nrows, ncols = ncols) | ||
cdef Matrix_gf2e_dense A = self.new_matrix(nrows = nrows, ncols = ncols) | ||
if ncols == 0 or nrows == 0: | ||
return A | ||
A._entries = mzed_submatrix(A._entries, self._entries, row, col, highr, highc) | ||
|
@@ -1388,8 +1398,8 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
sage: K.<a> = GF(2^8) | ||
sage: A = random_matrix(K,70,70) | ||
sage: f, s= A.__reduce__() | ||
sage: from sage.matrix.matrix_mod2e_dense import unpickle_matrix_mod2e_dense_v0 | ||
sage: f == unpickle_matrix_mod2e_dense_v0 | ||
sage: from sage.matrix.matrix_gf2e_dense import unpickle_matrix_gf2e_dense_v0 | ||
sage: f == unpickle_matrix_gf2e_dense_v0 | ||
True | ||
sage: f(*s) == A | ||
True | ||
|
@@ -1400,7 +1410,7 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
MS = MatrixSpace(GF(2), self._entries.x.nrows, self._entries.x.ncols) | ||
A = Matrix_mod2_dense.__new__(Matrix_mod2_dense, MS, 0, 0, 0, alloc = False) | ||
A._entries = mzd_copy( NULL, self._entries.x) | ||
return unpickle_matrix_mod2e_dense_v0, (A, self.base_ring(), self.nrows(), self.ncols()) | ||
return unpickle_matrix_gf2e_dense_v0, (A, self.base_ring(), self.nrows(), self.ncols()) | ||
|
||
def slice(self): | ||
r""" | ||
|
@@ -1587,22 +1597,29 @@ cdef class Matrix_mod2e_dense(matrix_dense.Matrix_dense): | |
mzed_cling(self._entries, v) | ||
mzd_slice_free(v) | ||
|
||
def unpickle_matrix_mod2e_dense_v0(Matrix_mod2_dense a, base_ring, nrows, ncols): | ||
""" | ||
def unpickle_matrix_gf2e_dense_v0(Matrix_mod2_dense a, base_ring, nrows, ncols): | ||
r""" | ||
EXAMPLE:: | ||
sage: K.<a> = GF(2^2) | ||
sage: A = random_matrix(K,10,10) | ||
sage: f, s= A.__reduce__() | ||
sage: from sage.matrix.matrix_mod2e_dense import unpickle_matrix_mod2e_dense_v0 | ||
sage: f == unpickle_matrix_mod2e_dense_v0 | ||
sage: from sage.matrix.matrix_gf2e_dense import unpickle_matrix_gf2e_dense_v0 | ||
sage: f == unpickle_matrix_gf2e_dense_v0 | ||
True | ||
sage: f(*s) == A | ||
True | ||
We can still unpickle pickles from before :trac:`19240`:: | ||
sage: old_pickle = 'x\x9c\x85RKo\xd3@\x10\xae\xdd$$\xdb&\xe5U\x1e-\x8f\xc2\xc9\x12RD#$\xce\xa0\xb4\x80\x07\xa2\xca\xc2\x07\x0e\xd5\xe2:\x1b\xdb\x8acg\x1c\xa7J\x85*!\xa4\x90\xe6\x07p\xe0\xc4\x01q\xe5\xc4\x19\xf5\xd0?\xc1\x81\xdf\x80\xb8q\x0b\xb3\x8eMS\xa1\x82V;;\xb3\xdf\xce\xf7\xcd\x8e\xe6\xb5j\xf7,GT;V\x1cy\x83\xf4\xe0\x9d\xb0Y\x13\xbc)\x82\x9e`\xfd\xa0\xeb\xd9m_\xf0\xbf1\xbe{\x97\xa1\xa2\x9d\xc6\xf0\x0f\x82,\x7f\x9d\xa1\xaa\x81\n\xb9m\x9c\xd7\xf4\xf1d2\x81-h\xc0#(\x03\x83\x15\xdas\xc9*\xc3\x13x\x0cu0\xd28\x97\x9e*(0\x9f\xfa\x1b\xd0\xd2\x7fH\x82\xb5\xf4\xa2@TO\xe19\x01I\xac\x136\x991\x9f\xa4\xf9&\xcd\x07i\xbe\xcb\xd4ib\t\xba\xa4\xf6\x02zIT\xd1\x8f2(u\x15\xfd\x9d<\xee@\x05V\xd3\x94E*\xb0\x0e\x0fH\xad\xa8\xbf\x97\xa0\r\x03\xfd\xf0\xb8\x1aU\xff\x92\x90\xe8?\xa5\xd6\x814_\xa5\xf9(\xcd\xafc\xe99\xe2\xd9\xa0\x06\xd4\xf5\xcf\xf2\xf2!\xbc\xd4\xdf\x90#\xc0\x8f\r\xccM\x1b\xdd\x8b\xa3\xbe\x1d\xf7#QmYv\x1cF{\xcc\x11\x81\x88<\x9b\xa71\xcf:\xce0\xaf\x9d\x96\xe3\x87a\xbb\xdf\xe5\x8e\x1f\xeeX>\xc3\x82\xb9\xb0\xe9\x05^,6=\xe17\xf1\xcc\xd0\xc0"u\xb0d\xe6wDl\xdd\x1fa)e\x8a\xbc\xc0\xe9U\xbd \x16\x8e\x88X\xc7j\x0b\x9e\x05\xc8L\xe5\x1e%.\x98\x8a5\xc4\xc5\xd9\xf7\xdd\xd0\xdf\x0b\xc2\x8eg\xf93.wZ\xb5\xc1\x94B\xf8\xa2#\x82\x98a\xf9\xffY\x12\xe3v\x18L\xff\x14Fl\xeb\x0ff\x10\xc4\xb0\xa2\xb9y\xcd-\xba%\xcd\xa5\x8ajT\xd1\x92\xa9\x0c\x86x\xb6a\xe6h\xf8\x02<g\xaa\xaf\xf6\xdd%\x89\xae\x13z\xfe \xc6\x0b\xfb1^4p\x99\x1e6\xc6\xd4\xebK\xdbx\xf9\xc4\x8f[Iw\xf8\x89\xef\xcbQf\xcfh\xe3\x95\x8c\xebj&\xb9\xe2.\x8f\x0c\\ui\x89\xf1x\xf4\xd6\xc0kf\xc1\xf1v\xad(\xc4\xeb\x89~\xfa\xf0\x06\xa8\xa4\x7f\x93\xf4\xd7\x0c\xbcE#\xad\x92\xfc\xed\xeao\xefX\\\x03' | ||
sage: loads(old_pickle) | ||
[ 0 a] | ||
[a + 1 1] | ||
""" | ||
from sage.matrix.matrix_space import MatrixSpace | ||
|
||
MS = MatrixSpace(base_ring, nrows, ncols) | ||
cdef Matrix_mod2e_dense A = Matrix_mod2e_dense.__new__(Matrix_mod2e_dense, MS, 0, 0, 0) | ||
cdef Matrix_gf2e_dense A = Matrix_gf2e_dense.__new__(Matrix_gf2e_dense, MS, 0, 0, 0) | ||
mzd_copy(A._entries.x, a._entries) | ||
return A |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.