diff --git a/README.md b/README.md
index af9942a178e5890d1b82391e2809fea73ccbcdc3..34ec1e91f9e6bd7185fce6b6b548a281e95cac0d 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 #### DESCRIPTION
 
-Cute Little R Functions contains 18 functions for R/RStudio that facilitate basic procedures in 1) object analysis, 2) object modification, 3) graphic handling and 4) log file management.
+Cute Little R Functions contains 19 functions for R/RStudio that facilitate basic procedures in 1) object analysis, 2) object modification, 3) graphic handling and 4) log file management.
 
 The function names are:
 
@@ -15,6 +15,7 @@ fun_rounding()	round a vector of values, if decimal, with the desired number of
 fun_90clock_matrix_rot()	90° clockwise matrix rotation
 fun_hexa_hsv_color_matrix()	convert a matrix made of numbers into a hexadecimal matrix for rgb colorization
 fun_by_case_matrix_op()	assemble several matrices of same dimensions by performing by case operation
+fun_mat_inv()	return the inverse of a square matrix when solve() cannot
 fun_window_width_resizing()	rescale the width of a window to open depending on the number of classes to plot
 fun_open_window()	open a pdf or screen (GUI) graphic window
 fun_graph_param_prior_plot()	very convenient to erase the axes for post plot axis redrawing using fun_feature_post_plot()
@@ -63,6 +64,11 @@ Check for updated versions (most recent tags) at https://gitlab.pasteur.fr/gmill
 
 #### WHAT'S NEW IN
 
+## v4.9.0
+
+1) fun_mat_inv() function added
+
+
 ## v4.8.0
 
 1) magnific argument removed in fun_feature_post_plot() because no need anymore
diff --git a/cute_little_R_functions.R b/cute_little_R_functions.R
index e5c61edd7aeba59cfe7bbfdfd9e6a276bd864ec1..847b0b85230a44b4e378109d20e3e98fd3ff1749 100644
--- a/cute_little_R_functions.R
+++ b/cute_little_R_functions.R
@@ -1,6 +1,6 @@
 ################################################################
 ##                                                            ##
-##     CUTE LITTLE R FUNCTIONS v4.8.0                         ##
+##     CUTE LITTLE R FUNCTIONS v4.9.0                         ##
 ##                                                            ##
 ##     Gael A. Millot                                         ##
 ##                                                            ##
@@ -11,7 +11,6 @@
 
 
 
-
 ################################ OUTLINE ################################
 
 
@@ -28,15 +27,16 @@
 ######## fun_90clock_matrix_rot() #### 90° clockwise matrix rotation    27
 ######## fun_hexa_hsv_color_matrix() #### Conversion of a numeric matrix into hexadecimal color matrix  28
 ######## fun_by_case_matrix_op() #### assembling of several matrices with operation 30
-################ Graphics   32
-######## fun_window_width_resizing() #### window width depending on classes to plot 33
-######## fun_open_window() #### Open a GUI or pdf graphic window    34
-######## fun_graph_param_prior_plot() #### Graph param before plotting  37
-######## fun_feature_post_plot() #### Graph param after plotting    41
-######## fun_close_specif_window() #### Closing specific graphic windows    52
-######## fun_var_trim_display() #### Display values from a quantitative variable and trim according to defined cut-offs 54
-################ Exporting results (text & tables)  62
-######## fun_export_data() #### Print string or data object into output file    62
+######## fun_mat_inv() #### return the inverse of a square matrix   33
+################ Graphics   34
+######## fun_window_width_resizing() #### window width depending on classes to plot 34
+######## fun_open_window() #### Open a GUI or pdf graphic window    35
+######## fun_graph_param_prior_plot() #### Graph param before plotting  39
+######## fun_feature_post_plot() #### Graph param after plotting    43
+######## fun_close_specif_window() #### Closing specific graphic windows    53
+######## fun_var_trim_display() #### Display values from a quantitative variable and trim according to defined cut-offs 55
+################ Exporting results (text & tables)  63
+######## fun_export_data() #### Print string or data object into output file    63
 
 
 ################################ FUNCTIONS ################################
@@ -225,63 +225,63 @@ fun_param_check <- function(data, data.name = NULL, class = NULL, typeof = NULL,
             if( ! is.null(get(arg.names[i2]))){
                 # script to execute
                 tempo.script <- '
-                problem <- TRUE ;
-                if(identical(text, paste0("NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){
-                text <- paste0("PROBLEM: THE ", data.name, " PARAMETER MUST BE ") ;
-                }else{
-                text <- paste0(text, " AND "); 
-                }
-                text <- paste0(text, toupper(arg.names[i2]), " ", get(arg.names[i2]))
-                '
-                if(typeof(data) == "double" & double.as.integer.allowed == TRUE & ((arg.names[i2] == "class" & get(arg.names[i2]) == "integer") | (arg.names[i2] == "typeof" & get(arg.names[i2]) == "integer"))){
-                    if(! all(data%%1 == 0)){ # to check integers (use %%, meaning the remaining of a division): see the precedent line
-                        eval(parse(text = tempo.script)) # execute tempo.script
-                    }
-                }else if(eval(parse(text = paste0(arg.names[i2], "(data)"))) != get(arg.names[i2])){
+problem <- TRUE ;
+if(identical(text, paste0("NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){
+text <- paste0("PROBLEM: THE ", data.name, " PARAMETER MUST BE ") ;
+}else{
+text <- paste0(text, " AND "); 
+}
+text <- paste0(text, toupper(arg.names[i2]), " ", get(arg.names[i2]))
+'
+            if(typeof(data) == "double" & double.as.integer.allowed == TRUE & ((arg.names[i2] == "class" & get(arg.names[i2]) == "integer") | (arg.names[i2] == "typeof" & get(arg.names[i2]) == "integer"))){
+                if(! all(data%%1 == 0)){ # to check integers (use %%, meaning the remaining of a division): see the precedent line
                     eval(parse(text = tempo.script)) # execute tempo.script
                 }
+            }else if(eval(parse(text = paste0(arg.names[i2], "(data)"))) != get(arg.names[i2])){
+                eval(parse(text = tempo.script)) # execute tempo.script
             }
-    }
-        }
-    if( ! is.null(prop)){
-        if(prop == TRUE){
-            if(any(data < 0 | data > 1, na.rm = TRUE)){
-                problem <- TRUE
-                if(identical(text, paste0("NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){
-                    text <- paste0("PROBLEM: ")
-                }else{
-                    text <- paste0(text, " AND ")
-                }
-                text <- paste0(text, "THE ", data.name, " PARAMETER MUST BE DECIMAL VALUES BETWEEN 0 AND 1")
             }
         }
     }
-    if(na.contain == FALSE & any(is.na(data)) == TRUE){
-        problem <- TRUE
-        if(identical(text, paste0("NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){
-            text <- paste0("PROBLEM: ")
-        }else{
-            text <- paste0(text, " AND ")
-        }
-        text <- paste0(text, "THE ", data.name, " PARAMETER CONTAINS NA WHILE NOT AUTHORIZED (na.contain ARGUMENT SET TO FALSE)")
-    }
-    if(neg.values == FALSE){
-        if(any(data < 0, na.rm = TRUE)){
+if( ! is.null(prop)){
+    if(prop == TRUE){
+        if(any(data < 0 | data > 1, na.rm = TRUE)){
             problem <- TRUE
             if(identical(text, paste0("NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){
                 text <- paste0("PROBLEM: ")
             }else{
                 text <- paste0(text, " AND ")
             }
-            text <- paste0(text, "THE ", data.name, " PARAMETER MUST NON NEGATIVE NUMERIC VALUES")
+            text <- paste0(text, "THE ", data.name, " PARAMETER MUST BE DECIMAL VALUES BETWEEN 0 AND 1")
         }
     }
-    if(print == TRUE & problem == TRUE){
-        cat(paste0("\n\n================\n\n", text, "\n\n================\n\n"))
+}
+if(na.contain == FALSE & any(is.na(data)) == TRUE){
+    problem <- TRUE
+    if(identical(text, paste0("NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){
+        text <- paste0("PROBLEM: ")
+    }else{
+        text <- paste0(text, " AND ")
     }
-    output <- list(problem = problem, text = text, param.name = data.name)
-    return(output)
+    text <- paste0(text, "THE ", data.name, " PARAMETER CONTAINS NA WHILE NOT AUTHORIZED (na.contain ARGUMENT SET TO FALSE)")
+}
+if(neg.values == FALSE){
+    if(any(data < 0, na.rm = TRUE)){
+        problem <- TRUE
+        if(identical(text, paste0("NO PROBLEM DETECTED FOR THE ", data.name, " PARAMETER"))){
+            text <- paste0("PROBLEM: ")
+        }else{
+            text <- paste0(text, " AND ")
+        }
+        text <- paste0(text, "THE ", data.name, " PARAMETER MUST NON NEGATIVE NUMERIC VALUES")
     }
+}
+if(print == TRUE & problem == TRUE){
+    cat(paste0("\n\n================\n\n", text, "\n\n================\n\n"))
+}
+output <- list(problem = problem, text = text, param.name = data.name)
+return(output)
+}
 
 
 ######## fun_object_info() #### Recovering object information
@@ -1534,6 +1534,71 @@ fun_by_case_matrix_op <- function(mat.list, kind.of.operation = "+"){
 }
 
 
+######## fun_mat_inv() #### return the inverse of a square matrix
+
+
+# Check OK: clear to go Apollo
+fun_mat_inv <- function(mat){
+    # AIM:
+    # return the inverse of a square matrix when solve() cannot
+    # REQUIRED FUNCTIONS
+    # fun_param_check()
+    # ARGUMENTS:
+    # mat: a square numeric matrix without NULL, NA, Inf or single case (dimension 1, 1) of 0
+    # RETURN
+    # the inversed matrix
+    # EXAMPLES
+    # mat1 = matrix(c(1,1,1,2,1,5,9,8,9), ncol = 3) ; fun_mat_inv(mat = mat1) # use solve()
+    # mat1 = matrix(c(0,0,0,0,0,0,0,0,0), ncol = 3) ; fun_mat_inv(mat = mat1) # use the trick
+    # mat1 = matrix(c(1,1,1,2,Inf,5,9,8,9), ncol = 3) ; fun_mat_inv(mat = mat1)
+    # mat1 = matrix(c(1,1,1,2,NA,5,9,8,9), ncol = 3) ; fun_mat_inv(mat = mat1)
+    # mat1 = matrix(c(1,2), ncol = 1) ; fun_mat_inv(mat = mat1)
+    # mat1 = matrix(0, ncol = 1) ; fun_mat_inv(mat = mat1)
+    # mat1 = matrix(2, ncol = 1) ; fun_mat_inv(mat = mat1)
+    # DEBUGGING
+    # mat = matrix(c(1,1,1,2,1,5,9,8,9), ncol = 3) # for function debugging
+    # required function checking
+    if(length(find("fun_param_check", mode = "function")) == 0){
+        tempo.cat <- paste0("\n\n================\n\nERROR IN fun_mat_inv(): REQUIRED fun_param_check() FUNCTION IS MISSING IN THE R ENVIRONMENT\n\n================\n\n")
+        stop(tempo.cat)
+    }
+    # end required function checking
+    # argument checking
+    arg.check <- NULL # for function debbuging
+    checked.arg.names <- NULL # for function debbuging
+    ee <- expression(arg.check <- c(arg.check, tempo$problem) , checked.arg.names <- c(checked.arg.names, tempo$param.name))
+    tempo <- fun_param_check(data = mat, class = "matrix", mode = "numeric") ; eval(ee)
+    if(any(arg.check) == TRUE){
+        stop() # nothing else because print = TRUE by default in fun_param_check()
+    }
+    # source("C:/Users/Gael/Documents/Git_versions_to_use/debugging_tools_for_r_dev-v1.2/r_debugging_tools-v1.2.R") ; eval(parse(text = str_basic_arg_check_dev)) ; eval(parse(text = str_arg_check_with_fun_param_check_dev)) # activate this line and use the function to check arguments status and if they have been checked using fun_param_check()
+    if(ncol(mat) != nrow(mat)){
+        tempo.cat <- paste0("\n\n================\n\nERROR IN fun_mat_inv(): mat ARGUMENT MUST BE A SQUARE MATRIX\n\n================\n\n")
+        stop(tempo.cat)
+    }
+    if(any(mat %in% c(Inf, -Inf, NA))){
+        tempo.cat <- paste0("\n\n================\n\nERROR IN fun_mat_inv(): mat ARGUMENT MUST BE A MATRIX WITHOUT Inf, -Inf OR NA\n\n================\n\n")
+        stop(tempo.cat)
+    }
+    if(all(mat == 0) & ncol(mat) == 1){
+        tempo.cat <- paste0("\n\n================\n\nERROR IN fun_mat_inv(): mat ARGUMENT CANNOT BE A SQUARE MATRIX MADE OF A SINGLE CASE OF 0\n\n================\n\n")
+        stop(tempo.cat)
+    }
+    # end argument checking
+    if(any(grepl(x = try(solve(mat), silent = TRUE)[], pattern = "Error"))){
+        tempo <- svd(mat)
+        val.critique <- which(tempo$d < 10^-8)
+        Diag.mod <- diag(1 / tempo$d)
+        for(i in val.critique){
+            Diag.mod[i, i] <- 0
+        }
+        return(tempo$v %*% Diag.mod %*% t(tempo$u))
+    }else{
+        return(solve(mat))
+    }
+}
+
+
 ################ Graphics
 
 
diff --git a/cute_little_R_functions.docx b/cute_little_R_functions.docx
index e51ba92c47dd802a8a581ccb77f4c883a3eff57e..12466d98d3c48e8ae08ea7b02c5f121a597b90f5 100644
Binary files a/cute_little_R_functions.docx and b/cute_little_R_functions.docx differ
diff --git a/examples_alone.txt b/examples_alone.txt
index b753c1c5c4defbc8b2ec0e392c936ad024015070..22e2f990b68cbc157f48e0d825754565d0ec053f 100644
--- a/examples_alone.txt
+++ b/examples_alone.txt
@@ -52,6 +52,14 @@ mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2, dimnames = list(LETTERS[1:4], letter
 mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2, dimnames = list(LETTERS[1:4], c(NA, NA))) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; fun_by_case_matrix_op(mat.list = list(mat1, mat2), kind.of.operation = "-")
 mat1 = matrix(c(1,1,1,2,1,5,9,8), ncol = 2, dimnames = list(c("A1", "A2", "A3", "A4"), letters[1:2])) ; mat2 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; mat3 = matrix(c(1,1,1,2,1,5,9,NA), ncol = 2, dimnames = list(LETTERS[1:4], letters[1:2])) ; fun_by_case_matrix_op(mat.list = list(mat1, mat2, mat3), kind.of.operation = "+")
 
+mat1 = matrix(c(1,1,1,2,1,5,9,8,9), ncol = 3) ; fun_mat_inv(mat = mat1) # use solve()
+mat1 = matrix(c(0,0,0,0,0,0,0,0,0), ncol = 3) ; fun_mat_inv(mat = mat1) # use the trick
+mat1 = matrix(c(1,1,1,2,Inf,5,9,8,9), ncol = 3) ; fun_mat_inv(mat = mat1)
+mat1 = matrix(c(1,1,1,2,NA,5,9,8,9), ncol = 3) ; fun_mat_inv(mat = mat1)
+mat1 = matrix(c(1,2), ncol = 1) ; fun_mat_inv(mat = mat1)
+mat1 = matrix(0, ncol = 1) ; fun_mat_inv(mat = mat1)
+mat1 = matrix(2, ncol = 1) ; fun_mat_inv(mat = mat1)
+
 fun_window_width_resizing(class.nb = 10, inches.per.class.nb = 0.2, ini.window.width = 7, inch.left.space = 1, inch.right.space = 1, boundarie.space = 0.5)
 
 fun_open_window(pdf.disp = FALSE, path.fun = "C:/Users/Gael/Desktop", pdf.name.file = "graph", width.fun = 7, height.fun = 7, paper = "special", no.pdf.overwrite = TRUE, return.output = TRUE)