-
Notifications
You must be signed in to change notification settings - Fork 18
Developer Guide
- Please install all dependencies according to the Advanced Install of Cytnx
- If you use conda environment, please activate it.
- Please install the gtest and doxygen
pip install gtest conda install doxygen
- Create your own branch from the branch dev-master:
- Clone the Cytnx repository and switch to that brach you created.
git clone https://github.com/Cytnx-dev/Cytnx.git cd Cytnx git checkout <YOUR_BRANCH>
- Modify the 'Install.sh' and build the Cytnx library:
sh Install.sh
cd build && ctest
Suppose <Cytnx_PATH> is the path you clone the Cytnx repository. You will see the following structure:
- include/: All of the header files of the user API will be here.
- src/: The implementation code will be here.
- tests/: The test code based on gtest (C++) will be here.
- pytest/: The test code based on pytest (python) will be here. But it is under maintenance currently.
- pybind/: Use the pybind11 to wrap the Cytnx library to Python. The code will be here.
- bm_test/: The benchmark test code will be here. But it is under maintenance currently.
- docs.doxygen: The configuration file of doxygen.
We take Svd for the Block type UniTensor as an example. We note that the corresponding API in python code:
S, U, Vt = cytnx.linalg.Svd(T)
And in the C++ code:
svds = cytnx::linalg::Svd(T);
Which means that this API is in the namespace cytnx::linalg. Then we write the API in the header file include/linalg.hpp:
699 std::vector<cytnx::UniTensor> Svd(const cytnx::UniTensor &Tin, const bool &is_UvT = true);
Note that the default argument needs to be set here, and the API is in the namespace cytnx::linalg.
-
We write the implementation code in the file src/linalg/Svd.cpp. The entry point of the API is:
411 std::vector<cytnx::UniTensor> Svd(const cytnx::UniTensor &Tin, const bool &is_UvT) { 412 // using rowrank to split the bond to form a matrix. 413 cytnx_error_msg(Tin.rowrank() < 1 || Tin.rank() == 1, 414 "[Svd][ERROR] Svd for UniTensor should have rank>1 and rowrank>0%s", "\n"); 415 416 cytnTin.is_diag(), 417 "[Svd][ERROR] Svd for diagonal UniTensor is trivial and currently not " 418 "support. Use other manipulation.%s", 419 "\n"); 420 421 std::vector<UniTensor> outCyT; 422 if (Tin.uten_type() == UTenType.Dense) { 423 _svd_Dense_UT(outCyT, Tin, is_UvT); 424 425 } else if (Tin.uten_type() == UTenType.Block) { 426 _svd_Block_UT(outCyT, Tin, is_UvT); 427 428 } else { 429 cytnx_error_msg(true, "[ERROR] only support svd for Dense and Block UniTensor.%s", "\n"); 430 431 } // is block form ? 432 433 return outCyT; 434 435 }; // Svd
After entering the API, we need to veriry the input date. If the input data is not correct, we will throw an error message via the cytnx_error_msg. For example in line 413:
413 cytnx_error_msg(Tin.rowrank() < 1 || Tin.rank() == 1, 414 "[Svd][ERROR] Svd for UniTensor should have rank>1 and rowrank>0%s", "\n");
Please take care if the GPU part still not support the API, you need to add the corresponding error message.
-
To Compile the code, we need to add the file src/linalg/Svd.cpp to the src/linalg/CMakeLists.txt:
46 Svd.cpp
We use the framework gtest to write the test code. The test code is in the directory tests. We take the Bond as an example. The test code is in the file tests/Bond_test.cpp:
3 TEST(Bond, EmptyBond) {
4 Bond bd;
5
6 EXPECT_EQ(bd.type(), BD_REG);
7
8 EXPECT_EQ(bd.dim(), 0);
9 }
-
You may need to use the EXPECT_EQ or EXPECT_TRUE to verify the result, or use the EXPECT_ANY_THROW to test if the input data is wrong but the code can catch it. Please refer to the gtest assertions for more information.
-
In order to avoid the contradiction of the declaration of the object of the function, we recommend that you can use another namespace. For example, we use the namespace SvdTest to test the Svd API. See the file tests/linalg/Svd_test.cpp.
-
To compile the test code, we also need to add the file in the tests/CMakeLists.txt:
10 Bond_test.cpp
-
To run the test code, you need to build the project first. You have two ways to build the project. One is that you can just enter the build directory and use the command:
make
The other way is that you can use the Install.sh to build the project:
sh Install.sh
To accelerate the compilation, you can comment the line in the Install.sh before you run the sh Install.sh:
194 #rm -rf build 195 #mkdir build . . . 199 #make install 200 # if DRUN_TESTS=ON, run tests 201 #ctest
After the build, you can run the test code in the build directory. There are two way. For example, if you want to test all Svd test case, you can use the command:
cd biuld ctest -R Svd
Or you can execute the test code in the build/tests/test_main.e:
cd build/tests ./test_main --gtest_filter=*Svd*
-
[optional] If you also want to test the python code, you can write the test code in the directory pytest. Becareful the nameing convention of the pytest. For more information, please refer to the pytest. Currently, the pytest is under maintenance. This step need to be done after you use pybind11 to wrap the Cytnx library to Python.(See step 6)
-
[optional] If you also want to test the benchmark code, you can write the test code in the directory bm_test. Currently, the bm_test is under maintenance. You may need to uncomment the corresponding code in the <Cytnx_PATH>/CMakeLists.txt about gtest and bm_test.
-
Write the cocumentation for your API based on the doxygen. For example, we write the documentation for the Svd API in the file include/linalg.hpp:
/** @brief Perform Singular-Value decomposition on a UniTensor using divide-and-conquer method. @details This function performs the Singular-Value decomposition on a UniTensor \p Tin. The result will depend on the rowrank of the UniTensor \p Tin. For more details, please refer to the documentation of the function Svd(const Tensor &Tin, const bool &is_UvT). */ std::vector<cytnx::UniTensor> Svd(const cytnx::UniTensor &Tin, const bool &is_UvT = true);
for UniTensor version. And for the Tensor version:
// Svd: //================================================== /** @brief Perform Singular-Value decomposition on a rank-2 Tensor (a @em matrix). @details This function will perform Singular-Value decomposition on a matrix (a rank-2 Tensor). That means givent a matrix \p Tin as \f$ M \f$, then the result will be: \f[ M = U S V^\dagger, \f] where \f$ U \f$ is a left uniform matrix, \f$ S \f$ is a diagonal matrix with singular values, and \f$ V^\dagger \f$ is the conjugate transpose of the right uniform matrix \f$ V \f$. Furthermore, \f$ U \f$ and \f$ V \f$ are unitary matrices, and \f$ S \f$ is a non-negative diagonal matrix. @param[in] Tin a Tensor, it should be a rank-2 tensor (matrix) @param[in] is_UvT whether need to return a left unitary matrix. @return @parblock [std::vector<Tensors>] 1. The first tensor is a 1-d tensor contanin the singular values 2. If \p is_UvT is true, then the tensors \f$ U,V^\dagger \f$ will be pushed back to the vector. @endparblock @pre The input tensor should be a rank-2 tensor (matrix). @see \ref Svd_truncate(const Tensor &Tin, const cytnx_uint64 &keepdim, const double &err, const bool &is_UvT, const unsigned int &return_err) "Svd_truncate" */ std::vector<Tensor> Svd(const Tensor &Tin, const bool &is_UvT = true);
Then you can generate the document by the command:
doxygen docs.doxygen
The entry point of the document is the file docs/html/index.html. And you can open it by the browser to check.
-
If this API is important, you can also add the document in the repo.
Take the Svd API as an example. We need to write the corresponding code in the file pybind/linalg_py.cpp:
m_linalg.def(
"Svd",
[](const cytnx::UniTensor &Tin, const bool &is_UvT) { return cytnx::linalg::Svd(Tin, is_UvT); },
py::arg("Tin"), py::arg("is_UvT") = true);
The default argument needs to consistent with the C++ API declared in the include/linalg.hpp.
std::vector<cytnx::UniTensor> Svd(const cytnx::UniTensor &Tin, const bool &is_UvT = true);
Sometimes we need to modify the file pybind/cytnx_py.cpp. You can use pytest to test your code after you build the project again.
- Bore you submit the code, you need to check the code can build successfully and pass all the test cases. Uncomment the line in the Install.sh:
194 rm -rf build
195 mkdir build
.
.
.
199 make install
200 if DRUN_TESTS=ON, run tests
201 ctest
and build the project again:
sh Install.sh
Check all of the test cases pass.
-
Use the pre-commit tool to check the coding style:
(1). If you have not installed the pre-commit tool, you can install it by the command:
conda install pre-commit
(2). Then you can run the following command to fix the coding style:
pre-commit run --all-files
You can run twice to make sure all of them are passed.
-
Submit the code to the repo and create a Pull Request:
(1). You can use the following command to submit the code to the repo:
git add . git commit -m "Your commit message" git push origin \<Your created branch\>
(2). Then you can create a Pull Request. After the PR is created, the CI will check the code and run the test cases.
(3). If the CI passes, please select the reviewer to review your code then wait to approve it to merge.
Then merge the code to the dev-master branch.
Here, just list something about when you want to create the new UniTensor type, say 'FermionUniTensor'.
You may need to add a type in the include/UniTensor.hpp:
34 class UniTensorType_class {
35 public:
36 enum : int {
37 Void = -99,
38 Dense = 0,
39 Sparse = 1,
40 Block = 2,
//Maybe some new type here, Ferimion = 3?
41 };
42 std::string getname(const int &ut_type);
43 };
and
95 friend class UniTensor; // allow wrapper to access the private elems
96 friend class DenseUniTensor;
97 // friend class SparseUniTensor;
98 friend class BlockUniTensor;
99 // friend class FermionUniTensor; <-- maybe like this
and another implementation in this file.
Also you may need to add the file src/FermionUniTensor.cpp to do the implementation.