Repository: feedzai/fairgbm (language: python)

Issue:
Update the readme (and create usage examples)
<!--
Please search your feature on previous issues and our feature requests consolidation hub (https://github.com/microsoft/LightGBM/issues/2302) before you open a new one.
-->

## Summary
Update the readme  file

## Motivation
The project Readme is describing itself as LightGBM. It is understood that this is a consequence of the fork, but  should be updated.

Update the readme (and create usage examples)
<!--
Please search your feature on previous issues and our feature requests consolidation hub (https://github.com/microsoft/LightGBM/issues/2302) before you open a new one.
-->

## Summary
Update the readme  file

## Motivation
The project Readme is describing itself as LightGBM. It is understood that this is a consequence of the fork, but  should be updated.



Discussion / hints:
Plus, create usage examples (notebooks and short code snippets in the Readme), and create sections for **Getting started**, **Contributing**, **Citing**, etc.

And leave a disclaimer stating that we diverged from Microsoft/LightGBM exactly at commit `fcd2453514a6ecd780121e4ea31a227559145451`
Plus, create usage examples (notebooks and short code snippets in the Readme), and create sections for **Getting started**, **Contributing**, **Citing**, etc.

And leave a disclaimer stating that we diverged from Microsoft/LightGBM exactly at commit `fcd2453514a6ecd780121e4ea31a227559145451`

Fix patch:
diff --git a/.appveyor.yml b/.appveyor.yml
deleted file mode 100644
index b7d9fe589..000000000
--- a/.appveyor.yml
+++ /dev/null
@@ -1,43 +0,0 @@
-version: 3.2.1.99.{build}
-
-image: Visual Studio 2015
-platform: x64
-configuration:  # a trick to construct a build matrix with multiple Python versions
-  - 3.7
-
-# only build pull requests and
-# commits to 'master'
-branches:
-  only:
-    - master
-
-environment:
-  matrix:
-    - COMPILER: MSVC
-      TASK: python
-    - COMPILER: MINGW
-      TASK: python
-
-clone_depth: 5
-
-install:
-  - git submodule update --init --recursive  # get `external_libs` folder
-  - set PATH=%PATH:C:\Program Files\Git\usr\bin;=%  # delete sh.exe from PATH (mingw32-make fix)
-  - set PATH=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%PATH%
-  - set PYTHON_VERSION=%CONFIGURATION%
-  - set CONDA_ENV="test-env"
-  - ps: |
-      switch ($env:PYTHON_VERSION) {
-          "3.6" {$env:MINICONDA = "C:\Miniconda36-x64"}
-          "3.7" {$env:MINICONDA = "C:\Miniconda37-x64"}
-          default {$env:MINICONDA = "C:\Miniconda37-x64"}
-      }
-      $env:PATH = "$env:MINICONDA;$env:MINICONDA\Scripts;$env:PATH"
-      $env:BUILD_SOURCESDIRECTORY = "$env:APPVEYOR_BUILD_FOLDER"
-      $env:LGB_VER = (Get-Content $env:APPVEYOR_BUILD_FOLDER\VERSION.txt).trim()
-
-build: false
-
-test_script:
-  - conda init powershell
-  - powershell.exe -ExecutionPolicy Bypass -File %APPVEYOR_BUILD_FOLDER%\.ci\test_windows.ps1
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
deleted file mode 100644
index 58398673c..000000000
--- a/.github/CODEOWNERS
+++ /dev/null
@@ -1,62 +0,0 @@
-# This file controls default reviewers for LightGBM code.
-# See https://help.github.com/en/articles/about-code-owners
-# for details
-#
-# Maintainers are encouraged to use their best discretion in
-# setting reviewers on PRs manually, but this file should
-# offer a reasonable automatic best-guess
-
-# catch-all rule (this only gets matched if no rules below match)
-*    @guolinke @StrikerRUS @jameslamb @shiyu1994
-
-# other catch-alls that will get matched if specific rules below are not matched
-*.R    @Laurae2 @jameslamb
-*.py    @StrikerRUS @chivee @wxchan @henry0312 @shiyu1994
-*.cpp    @guolinke @chivee @btrotta @shiyu1994
-*.h    @guolinke @chivee @btrotta @shiyu1994
-
-# main C++ code
-include/    @guolinke @chivee @btrotta @shiyu1994
-src/    @guolinke @chivee @btrotta @shiyu1994
-CMakeLists.txt    @guolinke @chivee @Laurae2 @jameslamb @wxchan @henry0312 @StrikerRUS @huanzhang12 @btrotta @shiyu1994
-tests/c_api_test/    @guolinke @chivee @btrotta @shiyu1994
-tests/cpp_tests/    @guolinke @chivee @btrotta @shiyu1994
-tests/data/    @guolinke @chivee @btrotta @shiyu1994
-windows/    @guolinke @chivee @btrotta @StrikerRUS @shiyu1994
-
-# R code
-build_r.R    @jameslamb @StrikerRUS
-build-cran-package.sh    @jameslamb @StrikerRUS
-R-package/    @Laurae2 @jameslamb
-
-# Python code
-python-package/    @StrikerRUS @chivee @wxchan @henry0312 @shiyu1994 @jameslamb
-
-# Dask integration
-python-package/lightgbm/dask.py    @jameslamb
-tests/python_package_test/test_dask.py    @jameslamb
-
-# helpers
-helpers/    @StrikerRUS @guolinke
-
-# CI administrative stuff
-.ci/    @StrikerRUS @jameslamb
-docs/    @StrikerRUS @jameslamb
-examples/     @StrikerRUS @jameslamb @guolinke
-*.yml    @StrikerRUS @jameslamb
-.vsts-ci.yml    @StrikerRUS @jameslamb
-
-# docker setup
-docker/    @StrikerRUS @jameslamb
-docker/dockerfile-cli    @guolinke @chivee @shiyu1994
-docker/gpu/    @huanzhang12
-docker/dockerfile-python    @StrikerRUS @chivee @wxchan @henry0312 @shiyu1994
-docker/dockerfile-r    @Laurae2 @jameslamb
-
-# GPU code
-docs/GPU-*.rst    @huanzhang12
-src/treelearner/gpu_tree_learner.cpp    @huanzhang12 @guolinke @chivee @shiyu1994
-src/treelearner/tree_learner.cpp    @huanzhang12 @guolinke @chivee @shiyu1994
-
-# JAVA code
-swig/    @guolinke @chivee @shiyu1994
diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.md b/.github/ISSUE_TEMPLATE/BUG_REPORT.md
index 0a90d330f..7e0822303 100644
--- a/.github/ISSUE_TEMPLATE/BUG_REPORT.md
+++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.md
@@ -11,9 +11,9 @@ about: Something isn't working as expected? Here is the right place to report.
 
 ## Environment info
 
-LightGBM version or commit hash:
+FairGBM version or commit hash:
 
-Command(s) you used to install LightGBM
+Command(s) you used to install FairGBM
 
 ```shell
 
diff --git a/.nuget/create_nuget.py b/.nuget/create_nuget.py
deleted file mode 100644
index 68a079bd1..000000000
--- a/.nuget/create_nuget.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# coding: utf-8
-"""Script for generating files with NuGet package metadata."""
-import datetime
-import os
-import sys
-from distutils.file_util import copy_file
-
-if __name__ == "__main__":
-    source = sys.argv[1]
-    current_dir = os.path.abspath(os.path.dirname(__file__))
-    linux_folder_path = os.path.join(current_dir, "runtimes", "linux-x64", "native")
-    if not os.path.exists(linux_folder_path):
-        os.makedirs(linux_folder_path)
-    osx_folder_path = os.path.join(current_dir, "runtimes", "osx-x64", "native")
-    if not os.path.exists(osx_folder_path):
-        os.makedirs(osx_folder_path)
-    windows_folder_path = os.path.join(current_dir, "runtimes", "win-x64", "native")
-    if not os.path.exists(windows_folder_path):
-        os.makedirs(windows_folder_path)
-    build_folder_path = os.path.join(current_dir, "build")
-    if not os.path.exists(build_folder_path):
-        os.makedirs(build_folder_path)
-    copy_file(os.path.join(source, "lib_lightgbm.so"), os.path.join(linux_folder_path, "lib_lightgbm.so"))
-    copy_file(os.path.join(source, "lib_lightgbm.dylib"), os.path.join(osx_folder_path, "lib_lightgbm.dylib"))
-    copy_file(os.path.join(source, "lib_lightgbm.dll"), os.path.join(windows_folder_path, "lib_lightgbm.dll"))
-    copy_file(os.path.join(source, "lightgbm.exe"), os.path.join(windows_folder_path, "lightgbm.exe"))
-    version = open(os.path.join(current_dir, os.path.pardir, 'VERSION.txt')).read().strip().replace('rc', '-rc')
-    nuget_str = rf"""<?xml version="1.0"?>
-    <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
-    <metadata>
-        <id>LightGBM</id>
-        <version>{version}</version>
-        <authors>Guolin Ke</authors>
-        <owners>Guolin Ke</owners>
-        <licenseUrl>https://github.com/microsoft/LightGBM/blob/master/LICENSE</licenseUrl>
-        <projectUrl>https://github.com/microsoft/LightGBM</projectUrl>
-        <requireLicenseAcceptance>false</requireLicenseAcceptance>
-        <description>A fast, distributed, high performance gradient boosting framework</description>
-        <copyright>Copyright {datetime.datetime.now().year} @ Microsoft</copyright>
-        <tags>machine-learning data-mining distributed native boosting gbdt</tags>
-        <dependencies> </dependencies>
-    </metadata>
-        <files>
-        <file src="build\**" target="build"/>
-        <file src="runtimes\**" target="runtimes"/>
-        </files>
-    </package>
-    """
-    prop_str = r"""
-    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-    <ItemGroup Condition="Exists('packages.config') OR
-                            Exists('$(MSBuildProjectName).packages.config') OR
-                            Exists('packages.$(MSBuildProjectName).config')">
-        <Content Include="$(MSBuildThisFileDirectory)/../runtimes/win-x64/native/*.dll"
-                Condition="'$(PlatformTarget)' == 'x64'">
-        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-        <Visible>false</Visible>
-        </Content>
-        <Content Include="$(MSBuildThisFileDirectory)/../runtimes/win-x64/native/*.exe"
-                Condition="'$(PlatformTarget)' == 'x64'">
-        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
-        <Visible>false</Visible>
-        </Content>
-    </ItemGroup>
-    </Project>
-    """
-    target_str = r"""
-    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-    <PropertyGroup>
-        <EnableLightGBMUnsupportedPlatformTargetCheck Condition="'$(EnableLightGBMUnsupportedPlatformTargetCheck)' == ''">true</EnableLightGBMUnsupportedPlatformTargetCheck>
-    </PropertyGroup>
-    <Target Name="_LightGBMCheckForUnsupportedPlatformTarget"
-            Condition="'$(EnableLightGBMUnsupportedPlatformTargetCheck)' == 'true'"
-            AfterTargets="_CheckForInvalidConfigurationAndPlatform">
-        <Error Condition="'$(PlatformTarget)' != 'x64' AND
-                        ('$(OutputType)' == 'Exe' OR '$(OutputType)'=='WinExe') AND
-                        !('$(TargetFrameworkIdentifier)' == '.NETCoreApp' AND '$(PlatformTarget)' == '')"
-            Text="LightGBM currently supports 'x64' processor architectures. Please ensure your application is targeting 'x64'." />
-    </Target>
-    </Project>
-    """
-    with open(os.path.join(current_dir, "LightGBM.nuspec"), "w") as nuget_file:
-        nuget_file.write(nuget_str)
-    with open(os.path.join(current_dir, "build", "LightGBM.props"), "w") as prop_file:
-        prop_file.write(prop_str)
-    with open(os.path.join(current_dir, "build", "LightGBM.targets"), "w") as target_file:
-        target_file.write(target_str)
diff --git a/.vsts-ci.yml b/.vsts-ci.yml
deleted file mode 100644
index 30702b314..000000000
--- a/.vsts-ci.yml
+++ /dev/null
@@ -1,382 +0,0 @@
-trigger:
-  branches:
-    include:
-    - master
-  tags:
-    include:
-    - v*
-pr:
-- master
-variables:
-  AZURE: 'true'
-  PYTHON_VERSION: 3.9
-  CONDA_ENV: test-env
-resources:
-  containers:
-  - container: ubuntu1404
-    image: lightgbm/vsts-agent:ubuntu-14.04
-  - container: ubuntu-latest
-    image: 'ubuntu:latest'
-    options: "--name ci-container -v /usr/bin/docker:/tmp/docker:ro"
-  - container: rbase
-    image: rocker/r-base
-jobs:
-###########################################
-- job: Linux
-###########################################
-  variables:
-    COMPILER: gcc
-    SETUP_CONDA: 'false'
-    OS_NAME: 'linux'
-    PRODUCES_ARTIFACTS: 'true'
-  pool: sh-ubuntu
-  container: ubuntu1404
-  strategy:
-    matrix:
-      regular:
-        TASK: regular
-      sdist:
-        TASK: sdist
-        PYTHON_VERSION: 3.7
-      bdist:
-        TASK: bdist
-      inference:
-        TASK: if-else
-      mpi_source:
-        TASK: mpi
-        METHOD: source
-        PYTHON_VERSION: 3.8
-      gpu_source:
-        TASK: gpu
-        METHOD: source
-      swig:
-        TASK: swig
-      cpp_tests:
-        TASK: cpp-tests
-  steps:
-  - script: |
-      echo "##vso[task.setvariable variable=BUILD_DIRECTORY]$BUILD_SOURCESDIRECTORY"
-      echo "##vso[task.setvariable variable=LGB_VER]$(head -n 1 VERSION.txt)"
-      echo "##vso[task.prependpath]$CONDA/bin"
-      AMDAPPSDK_PATH=$BUILD_SOURCESDIRECTORY/AMDAPPSDK
-      echo "##vso[task.setvariable variable=AMDAPPSDK_PATH]$AMDAPPSDK_PATH"
-      LD_LIBRARY_PATH=$AMDAPPSDK_PATH/lib/x86_64:$LD_LIBRARY_PATH
-      echo "##vso[task.setvariable variable=LD_LIBRARY_PATH]$LD_LIBRARY_PATH"
-      echo "##vso[task.setvariable variable=OPENCL_VENDOR_PATH]$AMDAPPSDK_PATH/etc/OpenCL/vendors"
-    displayName: 'Set variables'
-  - bash: $(Build.SourcesDirectory)/.ci/setup.sh
-    displayName: Setup
-  - bash: $(Build.SourcesDirectory)/.ci/test.sh
-    displayName: Test
-  - task: PublishBuildArtifacts@1
-    condition: and(succeeded(), in(variables['TASK'], 'regular', 'sdist', 'bdist', 'swig'), not(startsWith(variables['Build.SourceBranch'], 'refs/pull/')))
-    inputs:
-      pathtoPublish: '$(Build.ArtifactStagingDirectory)'
-      artifactName: PackageAssets
-      artifactType: container
-###########################################
-- job: Linux_latest
-###########################################
-  variables:
-    COMPILER: clang
-    DEBIAN_FRONTEND: 'noninteractive'
-    IN_UBUNTU_LATEST_CONTAINER: 'true'
-    OS_NAME: 'linux'
-    SETUP_CONDA: 'true'
-  pool: sh-ubuntu
-  container: ubuntu-latest
-  strategy:
-    matrix:
-      regular:
-        TASK: regular
-        PYTHON_VERSION: 3.6
-      sdist:
-        TASK: sdist
-      bdist:
-        TASK: bdist
-        PYTHON_VERSION: 3.8
-      inference:
-        TASK: if-else
-      mpi_source:
-        TASK: mpi
-        METHOD: source
-      mpi_pip:
-        TASK: mpi
-        METHOD: pip
-        PYTHON_VERSION: 3.8
-      mpi_wheel:
-        TASK: mpi
-        METHOD: wheel
-        PYTHON_VERSION: 3.7
-      gpu_source:
-        TASK: gpu
-        METHOD: source
-      gpu_pip:
-        TASK: gpu
-        METHOD: pip
-        PYTHON_VERSION: 3.6
-      gpu_wheel:
-        TASK: gpu
-        METHOD: wheel
-        PYTHON_VERSION: 3.7
-  steps:
-  - script: |
-      echo "##vso[task.setvariable variable=BUILD_DIRECTORY]$BUILD_SOURCESDIRECTORY"
-      echo "##vso[task.setvariable variable=LGB_VER]$(head -n 1 VERSION.txt)"
-      CONDA=$HOME/miniconda
-      echo "##vso[task.setvariable variable=CONDA]$CONDA"
-      echo "##vso[task.prependpath]$CONDA/bin"
-      AMDAPPSDK_PATH=$BUILD_SOURCESDIRECTORY/AMDAPPSDK
-      echo "##vso[task.setvariable variable=AMDAPPSDK_PATH]$AMDAPPSDK_PATH"
-      LD_LIBRARY_PATH=$AMDAPPSDK_PATH/lib/x86_64:$LD_LIBRARY_PATH
-      echo "##vso[task.setvariable variable=LD_LIBRARY_PATH]$LD_LIBRARY_PATH"
-      echo "##vso[task.setvariable variable=OPENCL_VENDOR_PATH]$AMDAPPSDK_PATH/etc/OpenCL/vendors"
-    displayName: 'Set variables'
-  # https://github.com/microsoft/azure-pipelines-agent/issues/2043#issuecomment-687983301
-  - script: |
-      /tmp/docker exec -t -u 0 ci-container \
-      sh -c "apt-get update && apt-get -o Dpkg::Options::="--force-confold" -y install sudo"
-    displayName: 'Install sudo'
-  - bash: $(Build.SourcesDirectory)/.ci/setup.sh
-    displayName: Setup
-  - bash: $(Build.SourcesDirectory)/.ci/test.sh
-    displayName: Test
-###########################################
-- job: QEMU_multiarch
-###########################################
-  variables:
-    COMPILER: gcc
-    OS_NAME: 'linux'
-    PRODUCES_ARTIFACTS: 'true'
-  pool:
-    vmImage: ubuntu-latest
-  timeoutInMinutes: 120
-  strategy:
-    matrix:
-      bdist:
-        TASK: bdist
-        ARCH: aarch64
-  steps:
-  - script: |
-      sudo apt-get update
-      sudo apt-get install --no-install-recommends -y \
-        binfmt-support \
-        qemu \
-        qemu-user \
-        qemu-user-static
-    displayName: 'Install QEMU'
-  - script: |
-      docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
-    displayName: 'Enable Docker multi-architecture support'
-  - script: |
-      export ROOT_DOCKER_FOLDER=/LightGBM
-      cat > docker.env <<EOF
-      AZURE=$AZURE
-      OS_NAME=$OS_NAME
-      COMPILER=$COMPILER
-      TASK=$TASK
-      METHOD=$METHOD
-      CONDA_ENV=$CONDA_ENV
-      PYTHON_VERSION=$PYTHON_VERSION
-      BUILD_DIRECTORY=$ROOT_DOCKER_FOLDER
-      LGB_VER=$(head -n 1 VERSION.txt)
-      PRODUCES_ARTIFACTS=$PRODUCES_ARTIFACTS
-      BUILD_ARTIFACTSTAGINGDIRECTORY=$BUILD_ARTIFACTSTAGINGDIRECTORY
-      EOF
-      cat > docker-script.sh <<EOF
-      export CONDA=\$HOME/miniconda
-      export PATH=\$CONDA/bin:\$PATH
-      $ROOT_DOCKER_FOLDER/.ci/setup.sh || exit -1
-      $ROOT_DOCKER_FOLDER/.ci/test.sh || exit -1
-      EOF
-      docker run \
-        --rm \
-        --env-file docker.env \
-        -v "$(Build.SourcesDirectory)":"$ROOT_DOCKER_FOLDER" \
-        -v "$(Build.ArtifactStagingDirectory)":"$(Build.ArtifactStagingDirectory)" \
-        "quay.io/pypa/manylinux2014_$ARCH" \
-        /bin/bash $ROOT_DOCKER_FOLDER/docker-script.sh
-    displayName: 'Setup and run tests'
-  - task: PublishBuildArtifacts@1
-    condition: and(succeeded(), in(variables['TASK'], 'bdist'), not(startsWith(variables['Build.SourceBranch'], 'refs/pull/')))
-    inputs:
-      pathtoPublish: '$(Build.ArtifactStagingDirectory)'
-      artifactName: PackageAssets
-      artifactType: container
-###########################################
-- job: macOS
-###########################################
-  variables:
-    COMPILER: clang
-    OS_NAME: 'macos'
-    PRODUCES_ARTIFACTS: 'true'
-  pool:
-    vmImage: 'macOS-10.14'
-  strategy:
-    matrix:
-      regular:
-        TASK: regular
-        PYTHON_VERSION: 3.7
-      sdist:
-        TASK: sdist
-        PYTHON_VERSION: 3.8
-      bdist:
-        TASK: bdist
-      swig:
-        TASK: swig
-      cpp_tests:
-        TASK: cpp-tests
-  steps:
-  - script: |
-      echo "##vso[task.setvariable variable=BUILD_DIRECTORY]$BUILD_SOURCESDIRECTORY"
-      echo "##vso[task.setvariable variable=LGB_VER]$(head -n 1 VERSION.txt)"
-      CONDA=$AGENT_HOMEDIRECTORY/miniconda
-      echo "##vso[task.setvariable variable=CONDA]$CONDA"
-      echo "##vso[task.prependpath]$CONDA/bin"
-      echo "##vso[task.setvariable variable=JAVA_HOME]$JAVA_HOME_8_X64"
-    displayName: 'Set variables'
-  - bash: $(Build.SourcesDirectory)/.ci/setup.sh
-    displayName: Setup
-  - bash: $(Build.SourcesDirectory)/.ci/test.sh
-    displayName: Test
-  - task: PublishBuildArtifacts@1
-    condition: and(succeeded(), in(variables['TASK'], 'regular', 'bdist', 'swig'), not(startsWith(variables['Build.SourceBranch'], 'refs/pull/')))
-    inputs:
-      pathtoPublish: '$(Build.ArtifactStagingDirectory)'
-      artifactName: PackageAssets
-      artifactType: container
-###########################################
-- job: Windows
-###########################################
-  pool:
-    vmImage: 'vs2017-win2016'
-  strategy:
-    matrix:
-      regular:
-        TASK: regular
-        PYTHON_VERSION: 3.6
-      sdist:
-        TASK: sdist
-        PYTHON_VERSION: 3.8
-      bdist:
-        TASK: bdist
-      swig:
-        TASK: swig
-      cpp_tests:
-        TASK: cpp-tests
-  steps:
-  - powershell: |
-      Write-Host "##vso[task.prependpath]$env:CONDA\Scripts"
-    displayName: 'Set Variables'
-  - script: |
-      cmd /c "powershell -ExecutionPolicy Bypass -File %BUILD_SOURCESDIRECTORY%/.ci/install_opencl.ps1"
-    condition: eq(variables['TASK'], 'bdist')
-    displayName: 'Install OpenCL'
-  - script: |
-      cmd /c "conda init powershell"
-      cmd /c "powershell -ExecutionPolicy Bypass -File %BUILD_SOURCESDIRECTORY%/.ci/test_windows.ps1"
-    displayName: Test
-  - task: PublishBuildArtifacts@1
-    condition: and(succeeded(), in(variables['TASK'], 'regular', 'bdist', 'swig'), not(startsWith(variables['Build.SourceBranch'], 'refs/pull/')))
-    inputs:
-      pathtoPublish: '$(Build.ArtifactStagingDirectory)'
-      artifactName: PackageAssets
-      artifactType: container
-###########################################
-- job: R_artifact
-###########################################
-  condition: not(startsWith(variables['Build.SourceBranch'], 'refs/pull/'))
-  pool:
-    vmImage: 'ubuntu-latest'
-  container: rbase
-  steps:
-  - script: |
-      LGB_VER=$(head -n 1 VERSION.txt | sed "s/rc/-/g")
-      sh build-cran-package.sh || exit -1
-      mv lightgbm_${LGB_VER}.tar.gz $(Build.ArtifactStagingDirectory)/lightgbm-${LGB_VER}-r-cran.tar.gz
-    displayName: 'Build CRAN R-package'
-  - task: PublishBuildArtifacts@1
-    condition: succeeded()
-    inputs:
-      pathtoPublish: $(Build.ArtifactStagingDirectory)
-      artifactName: R-package
-      artifactType: container
-
-###########################################
-- job: Package
-###########################################
-  dependsOn:
-  - Linux
-  - Linux_latest
-  - QEMU_multiarch
-  - macOS
-  - Windows
-  - R_artifact
-  condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/pull/')))
-  pool:
-    vmImage: 'ubuntu-latest'
-  steps:
-  # Create archives with complete source code included (with git submodules)
-  - task: ArchiveFiles@2
-    displayName: Create zip archive
-    condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
-    inputs:
-      rootFolderOrFile: $(Build.SourcesDirectory)
-      includeRootFolder: false
-      archiveType: zip
-      archiveFile: '$(Build.ArtifactStagingDirectory)/archives/LightGBM-complete_source_code_zip.zip'
-      replaceExistingArchive: true
-  - task: ArchiveFiles@2
-    displayName: Create tar.gz archive
-    condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
-    inputs:
-      rootFolderOrFile: $(Build.SourcesDirectory)
-      includeRootFolder: false
-      archiveType: tar
-      tarCompression: gz
-      archiveFile: '$(Build.ArtifactStagingDirectory)/archives/LightGBM-complete_source_code_tar_gz.tar.gz'
-      replaceExistingArchive: true
-  # Download all agent packages from all previous phases
-  - task: DownloadBuildArtifacts@0
-    displayName: Download package assets
-    inputs:
-      artifactName: PackageAssets
-      downloadPath: $(Build.SourcesDirectory)/binaries
-  - task: DownloadBuildArtifacts@0
-    displayName: Download R-package
-    condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
-    inputs:
-      artifactName: R-package
-      downloadPath: $(Build.SourcesDirectory)/R
-  - script: |
-      python "$(Build.SourcesDirectory)/.nuget/create_nuget.py" "$(Build.SourcesDirectory)/binaries/PackageAssets"
-    displayName: 'Create NuGet configuration files'
-  - task: NuGetCommand@2
-    inputs:
-      command: pack
-      packagesToPack: '$(Build.SourcesDirectory)/.nuget/*.nuspec'
-      packDestination: '$(Build.ArtifactStagingDirectory)/nuget'
-  - task: PublishBuildArtifacts@1
-    inputs:
-      pathtoPublish: '$(Build.ArtifactStagingDirectory)/nuget'
-      artifactName: NuGet
-      artifactType: container
-  - task: GitHubRelease@0
-    displayName: 'Create GitHub Release'
-    condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
-    inputs:
-      gitHubConnection: guolinke
-      repositoryName: '$(Build.Repository.Name)'
-      action: 'create'
-      target: '$(Build.SourceVersion)'
-      tagSource: 'auto'
-      title: '$(Build.SourceBranchName)'
-      assets: |
-        $(Build.SourcesDirectory)/binaries/PackageAssets/*
-        $(Build.SourcesDirectory)/R/R-package/*
-        $(Build.ArtifactStagingDirectory)/nuget/*.nupkg
-        $(Build.ArtifactStagingDirectory)/archives/*
-      assetUploadMode: 'delete'
-      isDraft: true
-      isPreRelease: false
-      addChangeLog: false
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
deleted file mode 100644
index e06693290..000000000
--- a/CODE_OF_CONDUCT.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# Microsoft Open Source Code of Conduct
-
-This code of conduct outlines expectations for participation in Microsoft-managed open source communities, as well as steps for reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all. People violating this code of conduct may be banned from the community.
-
-## Our open source communities strive to:
-
-* Be friendly and patient: Remember you might not be communicating in someone else's primary spoken or programming language, and others may not have your level of understanding.
-* Be welcoming: Our communities welcome and support people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, color, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
-* Be respectful: We are a world-wide community of professionals, and we conduct ourselves professionally. Disagreement is no excuse for poor behavior and poor manners. Disrespectful and unacceptable behavior includes, but is not limited to:
-    1. Violent threats or language.
-    2. Discriminatory or derogatory jokes and language.
-    3. Posting sexually explicit or violent material.
-    4. Posting, or threatening to post, people's personally identifying information ("doxing").
-    5. Insults, especially those using discriminatory terms or slurs.
-Behavior that could be perceived as sexual attention.
-Advocating for or encouraging any of the above behaviors.
-* Understand disagreements: Disagreements, both social and technical, are useful learning opportunities. Seek to understand the other viewpoints and resolve differences constructively.
-* This code is not exhaustive or complete. It serves to capture our common understanding of a productive, collaborative environment. We expect the code to be followed in spirit as much as in the letter.
-
-## Scope
-
-This code of conduct applies to all repos and communities for Microsoft-managed open source projects regardless of whether or not the repo explicitly calls out its use of this code. The code also applies in public spaces when an individual is representing a project or its community. Examples include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
-
-Note: Some Microsoft-managed communities have codes of conduct that pre-date this document and issue resolution process. While communities are not required to change their code, they are expected to use the resolution process outlined here. The review team will coordinate with the communities involved to address your concerns.
-
-## Reporting Code of Conduct Issues
-
-We encourage all communities to resolve issues on their own whenever possible. This builds a broader and deeper understanding and ultimately a healthier interaction. In the event that an issue cannot be resolved locally, please feel free to report your concerns by contacting opencode@microsoft.com. Your report will be handled in accordance with the issue resolution process described in the Code of Conduct FAQ.
-
-In your report please include:
-
-* Your contact information.
-* Names (real, usernames or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well.
-* Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public chat log), please include a link or attachment.
-* Any additional information that may be helpful.
-
-All reports will be reviewed by a multi-person team and will result in a response that is deemed necessary and appropriate to the circumstances. Where additional perspectives are needed, the team may seek insight from others with relevant expertise or experience. The confidentiality of the person reporting the incident will be kept at all times. Involved parties are never part of the review team.
-
-Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the review team may take any action they deem appropriate, including a permanent ban from the community.
-
-This code of conduct is based on the template established by the TODO Group and used by numerous other large communities (e.g., Facebook, Yahoo, Twitter, GitHub) and the Scope section from the Contributor Covenant version 1.4.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 312dcf0ea..7b8e9b1e8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,8 +1,21 @@
-LightGBM has been developed and used by many active community members. Your help is very valuable to make it better for everyone.
-
-- Check for the [Roadmap](https://github.com/microsoft/LightGBM/projects/1) and the [Feature Requests Hub](https://github.com/microsoft/LightGBM/issues/2302), and submit pull requests to address chosen issue. If you need development guideline, you can check the [Development Guide](https://github.com/microsoft/LightGBM/blob/master/docs/Development-Guide.rst) or directly ask us in Issues/Pull Requests.
-- Contribute to the [tests](https://github.com/microsoft/LightGBM/tree/master/tests) to make it more reliable.
-- Contribute to the [documentation](https://github.com/microsoft/LightGBM/tree/master/docs) to make it clearer for everyone.
-- Contribute to the [examples](https://github.com/microsoft/LightGBM/tree/master/examples) to share your experience with other users.
-- Add your stories and experience to [Awesome LightGBM](https://github.com/microsoft/LightGBM/blob/master/examples/README.md). If LightGBM helped you in a machine learning competition or some research application, we want to hear about it!
-- [Open an issue](https://github.com/microsoft/LightGBM/issues) to report problems or recommend new features.
+# Contributing
+
+We welcome external contributions from the open-source community.
+[Open an issue](https://github.com/feedzai/fairgbm/issues) to report problems or recommend new features.
+
+
+## Contributor List
+
+- André Cruz
+- Catarina Belém
+- Sérgio Jesus
+- Gonçalo Arsénio
+- Alberto Ferreira
+- João Veiga
+- Sara Guerreiro
+- João Bravo
+- Pedro Saleiro
+- Pedro Bizarro
+
+We also thank all [LightGBM contributors](https://github.com/microsoft/LightGBM/graphs/contributors) as the FairGBM 
+project was initially built upon that code-base.
diff --git a/LICENSE b/LICENSE
index 25df6b8c2..88748c606 100644
--- a/LICENSE
+++ b/LICENSE
@@ -207,6 +207,7 @@
 
 ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ###
 
+FairGBM extends Microsoft's LightGBM (made available under the MIT License below)
 
 The MIT License (MIT)
 
diff --git a/R-package/.Rbuildignore b/R-package/.Rbuildignore
deleted file mode 100644
index 3e552132c..000000000
--- a/R-package/.Rbuildignore
+++ /dev/null
@@ -1,49 +0,0 @@
-\.appveyor\.yml
-AUTOCONF_UBUNTU_VERSION
-^autom4te.cache/.*$
-^.*\.bin
-^build_r.R$
-\.clang-format
-^cran-comments\.md$
-^docs$
-^.*\.dll
-\.drone\.yml
-\.git
-\.gitkeep$
-^.*\.history
-^Makefile$
-^.*\.o
-^.*\.out
-^pkgdown$
-^recreate-configure\.sh$
-^.*\.so
-^src/build/.*$
-^src/CMakeLists.txt$
-^src/external_libs/compute/.appveyor.yml$
-^src/external_libs/compute/.coveralls.yml$
-^src/external_libs/compute/.travis.yml$
-^src/external_libs/compute/test/.*$
-^src/external_libs/compute/index.html$
-^src/external_libs/compute/.git$
-^src/external_libs/compute/.gitignore$
-^src/external_libs/compute/CONTRIBUTING.md$
-^src/external_libs/compute/README.md$
-src/external_libs/fast_double_parser/benchmarks
-src/external_libs/fast_double_parser/Makefile
-src/external_libs/fast_double_parser/.*\.md
-src/external_libs/fast_double_parser/tests
-src/external_libs/fast_double_parser/.*\.yaml
-src/external_libs/fast_double_parser/.*\.yml
-src/external_libs/fmt/.*\.md
-src/external_libs/fmt/.travis.yml
-src/external_libs/fmt/doc
-src/external_libs/fmt/support/Android\.mk
-src/external_libs/fmt/support/.*\.gradle
-src/external_libs/fmt/support/.*\.pro
-src/external_libs/fmt/support/.*\.py
-src/external_libs/fmt/support/rtd
-src/external_libs/fmt/support/.*sublime-syntax
-src/external_libs/fmt/support/Vagrantfile
-src/external_libs/fmt/support/.*\.xml
-src/external_libs/fmt/support/.*\.yml
-src/external_libs/fmt/test
diff --git a/R-package/AUTOCONF_UBUNTU_VERSION b/R-package/AUTOCONF_UBUNTU_VERSION
deleted file mode 100644
index 2eee9f218..000000000
--- a/R-package/AUTOCONF_UBUNTU_VERSION
+++ /dev/null
@@ -1,1 +0,0 @@
-2.69-11.1
diff --git a/R-package/DESCRIPTION b/R-package/DESCRIPTION
deleted file mode 100755
index 6e61f459c..000000000
--- a/R-package/DESCRIPTION
+++ /dev/null
@@ -1,60 +0,0 @@
-Package: lightgbm
-Type: Package
-Title: Light Gradient Boosting Machine
-Version: ~~VERSION~~
-Date: ~~DATE~~
-Authors@R: c(
-    person("Guolin", "Ke", email = "guolin.ke@microsoft.com", role = c("aut", "cre")),
-    person("Damien", "Soukhavong", email = "damien.soukhavong@skema.edu", role = c("aut")),
-    person("James", "Lamb", email="jaylamb20@gmail.com", role = c("aut")),
-    person("Qi", "Meng", role = c("aut")),
-    person("Thomas", "Finley", role = c("aut")),
-    person("Taifeng", "Wang", role = c("aut")),
-    person("Wei", "Chen", role = c("aut")),
-    person("Weidong", "Ma", role = c("aut")),
-    person("Qiwei", "Ye", role = c("aut")),
-    person("Tie-Yan", "Liu", role = c("aut")),
-    person("Yachen", "Yan", role = c("ctb")),
-    person("Microsoft Corporation", role = c("cph")),
-    person("Dropbox, Inc.", role = c("cph")),
-    person("Jay", "Loden", role = c("cph")),
-    person("Dave", "Daeschler", role = c("cph")),
-    person("Giampaolo", "Rodola", role = c("cph")),
-    person("Alberto", "Ferreira", role = c("ctb")),
-    person("Daniel", "Lemire", role = c("ctb")),
-    person("Victor", "Zverovich", role = c("cph")),
-    person("IBM Corporation", role = c("ctb"))
-    )
-Description: Tree based algorithms can be improved by introducing boosting frameworks. 
-    'LightGBM' is one such framework, based on Ke, Guolin et al. (2017) <https://papers.nips.cc/paper/6907-lightgbm-a-highly-efficient-gradient-boosting-decision>.
-    This package offers an R interface to work with it.
-    It is designed to be distributed and efficient with the following advantages:
-        1. Faster training speed and higher efficiency.
-        2. Lower memory usage.
-        3. Better accuracy.
-        4. Parallel learning supported.
-        5. Capable of handling large-scale data.
-    In recognition of these advantages, 'LightGBM' has been widely-used in many winning solutions of machine learning competitions.
-    Comparison experiments on public datasets suggest that 'LightGBM' can outperform existing boosting frameworks on both efficiency and accuracy, with significantly lower memory consumption. In addition, parallel experiments suggest that in certain circumstances, 'LightGBM' can achieve a linear speed-up in training time by using multiple machines.
-Encoding: UTF-8
-License: MIT + file LICENSE
-URL: https://github.com/Microsoft/LightGBM
-BugReports: https://github.com/Microsoft/LightGBM/issues
-NeedsCompilation: yes
-Biarch: true
-Suggests:
-    processx,
-    testthat
-Depends:
-    R (>= 3.5),
-    R6 (>= 2.0)
-Imports:
-    data.table (>= 1.9.6),
-    graphics,
-    jsonlite (>= 1.0),
-    Matrix (>= 1.1-0),
-    methods,
-    utils
-SystemRequirements:
-    C++11
-RoxygenNote: 7.1.1
diff --git a/R-package/LICENSE b/R-package/LICENSE
deleted file mode 100644
index f8c67ce8d..000000000
--- a/R-package/LICENSE
+++ /dev/null
@@ -1,2 +0,0 @@
-YEAR: 2016
-COPYRIGHT HOLDER: Microsoft Corporation
\ No newline at end of file
diff --git a/R-package/NAMESPACE b/R-package/NAMESPACE
deleted file mode 100644
index 92812c50d..000000000
--- a/R-package/NAMESPACE
+++ /dev/null
@@ -1,52 +0,0 @@
-# Generated by roxygen2: do not edit by hand
-
-S3method("dimnames<-",lgb.Dataset)
-S3method(dim,lgb.Dataset)
-S3method(dimnames,lgb.Dataset)
-S3method(getinfo,lgb.Dataset)
-S3method(predict,lgb.Booster)
-S3method(setinfo,lgb.Dataset)
-S3method(slice,lgb.Dataset)
-export(getinfo)
-export(lgb.Dataset)
-export(lgb.Dataset.construct)
-export(lgb.Dataset.create.valid)
-export(lgb.Dataset.save)
-export(lgb.Dataset.set.categorical)
-export(lgb.Dataset.set.reference)
-export(lgb.convert_with_rules)
-export(lgb.cv)
-export(lgb.dump)
-export(lgb.get.eval.result)
-export(lgb.importance)
-export(lgb.interprete)
-export(lgb.load)
-export(lgb.model.dt.tree)
-export(lgb.plot.importance)
-export(lgb.plot.interpretation)
-export(lgb.save)
-export(lgb.train)
-export(lgb.unloader)
-export(lightgbm)
-export(readRDS.lgb.Booster)
-export(saveRDS.lgb.Booster)
-export(setinfo)
-export(slice)
-import(methods)
-importFrom(Matrix,Matrix)
-importFrom(R6,R6Class)
-importFrom(data.table,":=")
-importFrom(data.table,as.data.table)
-importFrom(data.table,data.table)
-importFrom(data.table,rbindlist)
-importFrom(data.table,set)
-importFrom(data.table,setnames)
-importFrom(data.table,setorder)
-importFrom(data.table,setorderv)
-importFrom(graphics,barplot)
-importFrom(graphics,par)
-importFrom(jsonlite,fromJSON)
-importFrom(methods,is)
-importFrom(stats,quantile)
-importFrom(utils,read.delim)
-useDynLib(lib_lightgbm , .registration = TRUE)
diff --git a/R-package/R/aliases.R b/R-package/R/aliases.R
deleted file mode 100644
index cb2288fed..000000000
--- a/R-package/R/aliases.R
+++ /dev/null
@@ -1,128 +0,0 @@
-# Central location for parameter aliases.
-# See https://lightgbm.readthedocs.io/en/latest/Parameters.html#core-parameters
-
-# [description] List of respected parameter aliases specific to lgb.Dataset. Wrapped in a function to
-#               take advantage of lazy evaluation (so it doesn't matter what order
-#               R sources files during installation).
-# [return] A named list, where each key is a parameter relevant to lgb.DataSet and each value is a character
-#          vector of corresponding aliases.
-.DATASET_PARAMETERS <- function() {
-    return(
-        list(
-            "bin_construct_sample_cnt" = c(
-                "bin_construct_sample_cnt"
-                , "subsample_for_bin"
-            )
-            , "categorical_feature" = c(
-                "categorical_feature"
-                , "cat_feature"
-                , "categorical_column"
-                , "cat_column"
-            )
-            , "data_random_seed" = c(
-                "data_random_seed"
-                , "data_seed"
-            )
-            , "enable_bundle" = c(
-                "enable_bundle"
-                , "is_enable_bundle"
-                , "bundle"
-            )
-            , "feature_pre_filter" = "feature_pre_filter"
-            , "forcedbins_filename" = "forcedbins_filename"
-            , "group_column" = c(
-                "group_column"
-                , "group"
-                , "group_id"
-                , "query_column"
-                , "query"
-                , "query_id"
-            )
-            , "header" = c(
-                "header"
-                , "has_header"
-            )
-            , "ignore_column" = c(
-                "ignore_column"
-                , "ignore_feature"
-                , "blacklist"
-            )
-            , "is_enable_sparse" = c(
-                "is_enable_sparse"
-                , "is_sparse"
-                , "enable_sparse"
-                , "sparse"
-            )
-            , "label_column" = c(
-                "label_column"
-                , "label"
-            )
-            , "max_bin" = "max_bin"
-            , "max_bin_by_feature" = "max_bin_by_feature"
-            , "min_data_in_bin" = "min_data_in_bin"
-            , "pre_partition" = c(
-                "pre_partition"
-                , "is_pre_partition"
-            )
-            , "two_round" = c(
-                "two_round"
-                , "two_round_loading"
-                , "use_two_round_loading"
-            )
-            , "use_missing" = "use_missing"
-            , "weight_column" = c(
-                "weight_column"
-                , "weight"
-            )
-            , "zero_as_missing" = "zero_as_missing"
-        )
-    )
-}
-
-# [description] List of respected parameter aliases. Wrapped in a function to take advantage of
-#               lazy evaluation (so it doesn't matter what order R sources files during installation).
-# [return] A named list, where each key is a main LightGBM parameter and each value is a character
-#          vector of corresponding aliases.
-.PARAMETER_ALIASES <- function() {
-    learning_params <- list(
-        "boosting" = c(
-            "boosting"
-            , "boost"
-            , "boosting_type"
-        )
-        , "early_stopping_round" = c(
-            "early_stopping_round"
-            , "early_stopping_rounds"
-            , "early_stopping"
-            , "n_iter_no_change"
-        )
-        , "num_iterations" = c(
-            "num_iterations"
-            , "num_iteration"
-            , "n_iter"
-            , "num_tree"
-            , "num_trees"
-            , "num_round"
-            , "num_rounds"
-            , "num_boost_round"
-            , "n_estimators"
-        )
-    )
-    return(c(learning_params, .DATASET_PARAMETERS()))
-}
-
-# [description]
-#     Per https://github.com/microsoft/LightGBM/blob/master/docs/Parameters.rst#metric,
-#     a few different strings can be used to indicate "no metrics".
-# [returns]
-#     A character vector
-.NO_METRIC_STRINGS <- function() {
-    return(
-        c(
-            "na"
-            , "None"
-            , "null"
-            , "custom"
-        )
-    )
-}
diff --git a/R-package/R/callback.R b/R-package/R/callback.R
deleted file mode 100644
index 8d3f58222..000000000
--- a/R-package/R/callback.R
+++ /dev/null
@@ -1,462 +0,0 @@
-# constants that control naming in lists
-.EVAL_KEY <- function() {
-  return("eval")
-}
-.EVAL_ERR_KEY <- function() {
-  return("eval_err")
-}
-
-#' @importFrom R6 R6Class
-CB_ENV <- R6::R6Class(
-  "lgb.cb_env",
-  cloneable = FALSE,
-  public = list(
-    model = NULL,
-    iteration = NULL,
-    begin_iteration = NULL,
-    end_iteration = NULL,
-    eval_list = list(),
-    eval_err_list = list(),
-    best_iter = -1L,
-    best_score = NA,
-    met_early_stop = FALSE
-  )
-)
-
-cb.reset.parameters <- function(new_params) {
-
-  if (!identical(class(new_params), "list")) {
-    stop(sQuote("new_params"), " must be a list")
-  }
-
-  # Deparse parameter list
-  pnames  <- gsub("\\.", "_", names(new_params))
-  nrounds <- NULL
-
-  # Run some checks in the beginning
-  init <- function(env) {
-
-    # Check for model environment
-    if (is.null(env$model)) {
-      stop("Env should have a ", sQuote("model"))
-    }
-
-    # Store boosting rounds
-    nrounds <<- env$end_iteration - env$begin_iteration + 1L
-
-    # Check parameter names
-    for (n in pnames) {
-
-      # Set name
-      p <- new_params[[n]]
-
-      # Check if function for parameter
-      if (is.function(p)) {
-
-        # Check if requires at least two arguments
-        if (length(formals(p)) != 2L) {
-          stop("Parameter ", sQuote(n), " is a function but not of two arguments")
-        }
-
-        # Check if numeric or character
-      } else if (is.numeric(p) || is.character(p)) {
-
-        # Check if length is matching
-        if (length(p) != nrounds) {
-          stop("Length of ", sQuote(n), " has to be equal to length of ", sQuote("nrounds"))
-        }
-
-      } else {
-
-        stop("Parameter ", sQuote(n), " is not a function or a vector")
-
-      }
-
-    }
-
-    return(invisible(NULL))
-
-  }
-
-  callback <- function(env) {
-
-    # Check if rounds is null
-    if (is.null(nrounds)) {
-      init(env = env)
-    }
-
-    # Store iteration
-    i <- env$iteration - env$begin_iteration
-
-    # Apply list on parameters
-    pars <- lapply(new_params, function(p) {
-      if (is.function(p)) {
-        return(p(i, nrounds))
-      }
-      p[i]
-    })
-
-    if (!is.null(env$model)) {
-      return(env$model$reset_parameter(params = pars))
-    }
-
-    return(invisible(NULL))
-
-  }
-
-  attr(callback, "call") <- match.call()
-  attr(callback, "is_pre_iteration") <- TRUE
-  attr(callback, "name") <- "cb.reset.parameters"
-  return(callback)
-}
-
-# Format the evaluation metric string
-format.eval.string <- function(eval_res, eval_err = NULL) {
-
-  # Check for empty evaluation string
-  if (is.null(eval_res) || length(eval_res) == 0L) {
-    stop("no evaluation results")
-  }
-
-  # Check for empty evaluation error
-  if (!is.null(eval_err)) {
-    return(sprintf("%s\'s %s:%g+%g", eval_res$data_name, eval_res$name, eval_res$value, eval_err))
-  } else {
-    return(sprintf("%s\'s %s:%g", eval_res$data_name, eval_res$name, eval_res$value))
-  }
-
-}
-
-merge.eval.string <- function(env) {
-
-  # Check length of evaluation list
-  if (length(env$eval_list) <= 0L) {
-    return("")
-  }
-
-  # Get evaluation
-  msg <- list(sprintf("[%d]:", env$iteration))
-
-  # Set if evaluation error
-  is_eval_err <- length(env$eval_err_list) > 0L
-
-  # Loop through evaluation list
-  for (j in seq_along(env$eval_list)) {
-
-    # Store evaluation error
-    eval_err <- NULL
-    if (isTRUE(is_eval_err)) {
-      eval_err <- env$eval_err_list[[j]]
-    }
-
-    # Set error message
-    msg <- c(msg, format.eval.string(eval_res = env$eval_list[[j]], eval_err = eval_err))
-
-  }
-
-  return(paste0(msg, collapse = "  "))
-
-}
-
-cb.print.evaluation <- function(period = 1L) {
-
-  # Create callback
-  callback <- function(env) {
-
-    # Check if period is at least 1 or more
-    if (period > 0L) {
-
-      # Store iteration
-      i <- env$iteration
-
-      # Check if iteration matches moduo
-      if ((i - 1L) %% period == 0L || is.element(i, c(env$begin_iteration, env$end_iteration))) {
-
-        # Merge evaluation string
-        msg <- merge.eval.string(env = env)
-
-        # Check if message is existing
-        if (nchar(msg) > 0L) {
-          print(merge.eval.string(env = env))
-        }
-
-      }
-
-    }
-
-    return(invisible(NULL))
-
-  }
-
-  # Store attributes
-  attr(callback, "call") <- match.call()
-  attr(callback, "name") <- "cb.print.evaluation"
-
-  return(callback)
-
-}
-
-cb.record.evaluation <- function() {
-
-  # Create callback
-  callback <- function(env) {
-
-    if (length(env$eval_list) <= 0L) {
-      return()
-    }
-
-    # Set if evaluation error
-    is_eval_err <- length(env$eval_err_list) > 0L
-
-    # Check length of recorded evaluation
-    if (length(env$model$record_evals) == 0L) {
-
-      # Loop through each evaluation list element
-      for (j in seq_along(env$eval_list)) {
-
-        # Store names
-        data_name <- env$eval_list[[j]]$data_name
-        name <- env$eval_list[[j]]$name
-        env$model$record_evals$start_iter <- env$begin_iteration
-
-        # Check if evaluation record exists
-        if (is.null(env$model$record_evals[[data_name]])) {
-          env$model$record_evals[[data_name]] <- list()
-        }
-
-        # Create dummy lists
-        env$model$record_evals[[data_name]][[name]] <- list()
-        env$model$record_evals[[data_name]][[name]][[.EVAL_KEY()]] <- list()
-        env$model$record_evals[[data_name]][[name]][[.EVAL_ERR_KEY()]] <- list()
-
-      }
-
-    }
-
-    # Loop through each evaluation list element
-    for (j in seq_along(env$eval_list)) {
-
-      # Get evaluation data
-      eval_res <- env$eval_list[[j]]
-      eval_err <- NULL
-      if (isTRUE(is_eval_err)) {
-        eval_err <- env$eval_err_list[[j]]
-      }
-
-      # Store names
-      data_name <- eval_res$data_name
-      name <- eval_res$name
-
-      # Store evaluation data
-      env$model$record_evals[[data_name]][[name]][[.EVAL_KEY()]] <- c(
-        env$model$record_evals[[data_name]][[name]][[.EVAL_KEY()]]
-        , eval_res$value
-      )
-      env$model$record_evals[[data_name]][[name]][[.EVAL_ERR_KEY()]] <- c(
-        env$model$record_evals[[data_name]][[name]][[.EVAL_ERR_KEY()]]
-        , eval_err
-      )
-
-    }
-
-    return(invisible(NULL))
-
-  }
-
-  # Store attributes
-  attr(callback, "call") <- match.call()
-  attr(callback, "name") <- "cb.record.evaluation"
-
-  return(callback)
-
-}
-
-cb.early.stop <- function(stopping_rounds, first_metric_only = FALSE, verbose = TRUE) {
-
-  factor_to_bigger_better <- NULL
-  best_iter <- NULL
-  best_score <- NULL
-  best_msg <- NULL
-  eval_len <- NULL
-
-  # Initialization function
-  init <- function(env) {
-
-    # Early stopping cannot work without metrics
-    if (length(env$eval_list) == 0L) {
-      stop("For early stopping, valids must have at least one element")
-    }
-
-    # Store evaluation length
-    eval_len <<- length(env$eval_list)
-
-    # Check if verbose or not
-    if (isTRUE(verbose)) {
-      msg <- paste0(
-        "Will train until there is no improvement in "
-        , stopping_rounds
-        , " rounds."
-      )
-      print(msg)
-    }
-
-    # Internally treat everything as a maximization task
-    factor_to_bigger_better <<- rep.int(1.0, eval_len)
-    best_iter <<- rep.int(-1L, eval_len)
-    best_score <<- rep.int(-Inf, eval_len)
-    best_msg <<- list()
-
-    # Loop through evaluation elements
-    for (i in seq_len(eval_len)) {
-
-      # Prepend message
-      best_msg <<- c(best_msg, "")
-
-      # Internally treat everything as a maximization task
-      if (!isTRUE(env$eval_list[[i]]$higher_better)) {
-        factor_to_bigger_better[i] <<- -1.0
-      }
-
-    }
-
-    return(invisible(NULL))
-
-  }
-
-  # Create callback
-  callback <- function(env, finalize = FALSE) {
-
-    # Check for empty evaluation
-    if (is.null(eval_len)) {
-      init(env = env)
-    }
-
-    # Store iteration
-    cur_iter <- env$iteration
-
-    # By default, any metric can trigger early stopping. This can be disabled
-    # with 'first_metric_only = TRUE'
-    if (isTRUE(first_metric_only)) {
-      evals_to_check <- 1L
-    } else {
-      evals_to_check <- seq_len(eval_len)
-    }
-
-    # Loop through evaluation
-    for (i in evals_to_check) {
-
-      # Store score
-      score <- env$eval_list[[i]]$value * factor_to_bigger_better[i]
-
-        # Check if score is better
-        if (score > best_score[i]) {
-
-          # Store new scores
-          best_score[i] <<- score
-          best_iter[i] <<- cur_iter
-
-          # Prepare to print if verbose
-          if (verbose) {
-            best_msg[[i]] <<- as.character(merge.eval.string(env = env))
-          }
-
-        } else {
-
-          # Check if early stopping is required
-          if (cur_iter - best_iter[i] >= stopping_rounds) {
-
-            # Check if model is not null
-            if (!is.null(env$model)) {
-              env$model$best_score <- best_score[i]
-              env$model$best_iter <- best_iter[i]
-            }
-
-            # Print message if verbose
-            if (isTRUE(verbose)) {
-
-              print(paste0("Early stopping, best iteration is: ", best_msg[[i]]))
-
-            }
-
-            # Store best iteration and stop
-            env$best_iter <- best_iter[i]
-            env$met_early_stop <- TRUE
-          }
-
-        }
-
-      if (!isTRUE(env$met_early_stop) && cur_iter == env$end_iteration) {
-        # Check if model is not null
-        if (!is.null(env$model)) {
-          env$model$best_score <- best_score[i]
-          env$model$best_iter <- best_iter[i]
-        }
-
-        # Print message if verbose
-        if (isTRUE(verbose)) {
-          print(paste0("Did not meet early stopping, best iteration is: ", best_msg[[i]]))
-        }
-
-        # Store best iteration and stop
-        env$best_iter <- best_iter[i]
-        env$met_early_stop <- TRUE
-      }
-    }
-
-    return(invisible(NULL))
-
-  }
-
-  attr(callback, "call") <- match.call()
-  attr(callback, "name") <- "cb.early.stop"
-
-  return(callback)
-
-}
-
-# Extract callback names from the list of callbacks
-callback.names <- function(cb_list) {
-  return(unlist(lapply(cb_list, attr, "name")))
-}
-
-add.cb <- function(cb_list, cb) {
-
-  # Combine two elements
-  cb_list <- c(cb_list, cb)
-
-  # Set names of elements
-  names(cb_list) <- callback.names(cb_list = cb_list)
-
-  # Check for existence
-  if ("cb.early.stop" %in% names(cb_list)) {
-
-    # Concatenate existing elements
-    cb_list <- c(cb_list, cb_list["cb.early.stop"])
-
-    # Remove only the first one
-    cb_list["cb.early.stop"] <- NULL
-
-  }
-
-  # Return element
-  return(cb_list)
-
-}
-
-categorize.callbacks <- function(cb_list) {
-
-  # Check for pre-iteration or post-iteration
-  return(
-    list(
-      pre_iter = Filter(function(x) {
-        pre <- attr(x, "is_pre_iteration")
-        !is.null(pre) && pre
-      }, cb_list),
-      post_iter = Filter(function(x) {
-        pre <- attr(x, "is_pre_iteration")
-        is.null(pre) || !pre
-      }, cb_list)
-    )
-  )
-
-}
diff --git a/R-package/R/lgb.Booster.R b/R-package/R/lgb.Booster.R
deleted file mode 100644
index a3a6ae90d..000000000
--- a/R-package/R/lgb.Booster.R
+++ /dev/null
@@ -1,1130 +0,0 @@
-#' @importFrom R6 R6Class
-Booster <- R6::R6Class(
-  classname = "lgb.Booster",
-  cloneable = FALSE,
-  public = list(
-
-    best_iter = -1L,
-    best_score = NA_real_,
-    params = list(),
-    record_evals = list(),
-
-    # Finalize will free up the handles
-    finalize = function() {
-
-      # Check the need for freeing handle
-      if (!lgb.is.null.handle(x = private$handle)) {
-
-        # Freeing up handle
-        .Call(
-          LGBM_BoosterFree_R
-          , private$handle
-        )
-        private$handle <- NULL
-
-      }
-
-      return(invisible(NULL))
-
-    },
-
-    # Initialize will create a starter booster
-    initialize = function(params = list(),
-                          train_set = NULL,
-                          modelfile = NULL,
-                          model_str = NULL,
-                          ...) {
-
-      # Create parameters and handle
-      params <- append(params, list(...))
-      handle <- lgb.null.handle()
-
-      # Attempts to create a handle for the dataset
-      try({
-
-        # Check if training dataset is not null
-        if (!is.null(train_set)) {
-          # Check if training dataset is lgb.Dataset or not
-          if (!lgb.check.r6.class(object = train_set, name = "lgb.Dataset")) {
-            stop("lgb.Booster: Can only use lgb.Dataset as training data")
-          }
-          train_set_handle <- train_set$.__enclos_env__$private$get_handle()
-          params <- modifyList(params, train_set$get_params())
-          params_str <- lgb.params2str(params = params)
-          # Store booster handle
-          .Call(
-            LGBM_BoosterCreate_R
-            , train_set_handle
-            , params_str
-            , handle
-          )
-
-          # Create private booster information
-          private$train_set <- train_set
-          private$train_set_version <- train_set$.__enclos_env__$private$version
-          private$num_dataset <- 1L
-          private$init_predictor <- train_set$.__enclos_env__$private$predictor
-
-          # Check if predictor is existing
-          if (!is.null(private$init_predictor)) {
-
-            # Merge booster
-            .Call(
-              LGBM_BoosterMerge_R
-              , handle
-              , private$init_predictor$.__enclos_env__$private$handle
-            )
-
-          }
-
-          # Check current iteration
-          private$is_predicted_cur_iter <- c(private$is_predicted_cur_iter, FALSE)
-
-        } else if (!is.null(modelfile)) {
-
-          # Do we have a model file as character?
-          if (!is.character(modelfile)) {
-            stop("lgb.Booster: Can only use a string as model file path")
-          }
-
-          # Create booster from model
-          .Call(
-            LGBM_BoosterCreateFromModelfile_R
-            , modelfile
-            , handle
-          )
-
-        } else if (!is.null(model_str)) {
-
-          # Do we have a model_str as character?
-          if (!is.character(model_str)) {
-            stop("lgb.Booster: Can only use a string as model_str")
-          }
-
-          # Create booster from model
-          .Call(
-            LGBM_BoosterLoadModelFromString_R
-            , model_str
-            , handle
-          )
-
-        } else {
-
-          # Booster non existent
-          stop(
-            "lgb.Booster: Need at least either training dataset, "
-            , "model file, or model_str to create booster instance"
-          )
-
-        }
-
-      })
-
-      # Check whether the handle was created properly if it was not stopped earlier by a stop call
-      if (isTRUE(lgb.is.null.handle(x = handle))) {
-
-        stop("lgb.Booster: cannot create Booster handle")
-
-      } else {
-
-        # Create class
-        class(handle) <- "lgb.Booster.handle"
-        private$handle <- handle
-        private$num_class <- 1L
-        .Call(
-          LGBM_BoosterGetNumClasses_R
-          , private$handle
-          , private$num_class
-        )
-
-      }
-
-      self$params <- params
-
-      return(invisible(NULL))
-
-    },
-
-    # Set training data name
-    set_train_data_name = function(name) {
-
-      # Set name
-      private$name_train_set <- name
-      return(invisible(self))
-
-    },
-
-    # Add validation data
-    add_valid = function(data, name) {
-
-      # Check if data is lgb.Dataset
-      if (!lgb.check.r6.class(object = data, name = "lgb.Dataset")) {
-        stop("lgb.Booster.add_valid: Can only use lgb.Dataset as validation data")
-      }
-
-      # Check if predictors are identical
-      if (!identical(data$.__enclos_env__$private$predictor, private$init_predictor)) {
-        stop(
-          "lgb.Booster.add_valid: Failed to add validation data; "
-          , "you should use the same predictor for these data"
-        )
-      }
-
-      # Check if names are character
-      if (!is.character(name)) {
-        stop("lgb.Booster.add_valid: Can only use characters as data name")
-      }
-
-      # Add validation data to booster
-      .Call(
-        LGBM_BoosterAddValidData_R
-        , private$handle
-        , data$.__enclos_env__$private$get_handle()
-      )
-
-      # Store private information
-      private$valid_sets <- c(private$valid_sets, data)
-      private$name_valid_sets <- c(private$name_valid_sets, name)
-      private$num_dataset <- private$num_dataset + 1L
-      private$is_predicted_cur_iter <- c(private$is_predicted_cur_iter, FALSE)
-
-      return(invisible(self))
-
-    },
-
-    # Reset parameters of booster
-    reset_parameter = function(params, ...) {
-
-      if (methods::is(self$params, "list")) {
-        params <- modifyList(self$params, params)
-      }
-
-      params <- modifyList(params, list(...))
-      params_str <- lgb.params2str(params = params)
-
-      .Call(
-        LGBM_BoosterResetParameter_R
-        , private$handle
-        , params_str
-      )
-      self$params <- params
-
-      return(invisible(self))
-
-    },
-
-    # Perform boosting update iteration
-    update = function(train_set = NULL, fobj = NULL) {
-
-      if (is.null(train_set)) {
-        if (private$train_set$.__enclos_env__$private$version != private$train_set_version) {
-          train_set <- private$train_set
-        }
-      }
-
-      # Check if training set is not null
-      if (!is.null(train_set)) {
-
-        # Check if training set is lgb.Dataset
-        if (!lgb.check.r6.class(object = train_set, name = "lgb.Dataset")) {
-          stop("lgb.Booster.update: Only can use lgb.Dataset as training data")
-        }
-
-        # Check if predictors are identical
-        if (!identical(train_set$predictor, private$init_predictor)) {
-          stop("lgb.Booster.update: Change train_set failed, you should use the same predictor for these data")
-        }
-
-        # Reset training data on booster
-        .Call(
-          LGBM_BoosterResetTrainingData_R
-          , private$handle
-          , train_set$.__enclos_env__$private$get_handle()
-        )
-
-        # Store private train set
-        private$train_set <- train_set
-        private$train_set_version <- train_set$.__enclos_env__$private$version
-
-      }
-
-      # Check if objective is empty
-      if (is.null(fobj)) {
-        if (private$set_objective_to_none) {
-          stop("lgb.Booster.update: cannot update due to null objective function")
-        }
-        # Boost iteration from known objective
-        .Call(
-          LGBM_BoosterUpdateOneIter_R
-          , private$handle
-        )
-
-      } else {
-
-        # Check if objective is function
-        if (!is.function(fobj)) {
-          stop("lgb.Booster.update: fobj should be a function")
-        }
-        if (!private$set_objective_to_none) {
-          self$reset_parameter(params = list(objective = "none"))
-          private$set_objective_to_none <- TRUE
-        }
-        # Perform objective calculation
-        gpair <- fobj(private$inner_predict(1L), private$train_set)
-
-        # Check for gradient and hessian as list
-        if (is.null(gpair$grad) || is.null(gpair$hess)) {
-          stop("lgb.Booster.update: custom objective should
-            return a list with attributes (hess, grad)")
-        }
-
-        # Return custom boosting gradient/hessian
-        .Call(
-          LGBM_BoosterUpdateOneIterCustom_R
-          , private$handle
-          , gpair$grad
-          , gpair$hess
-          , length(gpair$grad)
-        )
-
-      }
-
-      # Loop through each iteration
-      for (i in seq_along(private$is_predicted_cur_iter)) {
-        private$is_predicted_cur_iter[[i]] <- FALSE
-      }
-
-      return(invisible(self))
-
-    },
-
-    # Return one iteration behind
-    rollback_one_iter = function() {
-
-      # Return one iteration behind
-      .Call(
-        LGBM_BoosterRollbackOneIter_R
-        , private$handle
-      )
-
-      # Loop through each iteration
-      for (i in seq_along(private$is_predicted_cur_iter)) {
-        private$is_predicted_cur_iter[[i]] <- FALSE
-      }
-
-      return(invisible(self))
-
-    },
-
-    # Get current iteration
-    current_iter = function() {
-
-      cur_iter <- 0L
-      .Call(
-        LGBM_BoosterGetCurrentIteration_R
-        , private$handle
-        , cur_iter
-      )
-      return(cur_iter)
-
-    },
-
-    # Get upper bound
-    upper_bound = function() {
-
-      upper_bound <- 0.0
-      .Call(
-        LGBM_BoosterGetUpperBoundValue_R
-        , private$handle
-        , upper_bound
-      )
-      return(upper_bound)
-
-    },
-
-    # Get lower bound
-    lower_bound = function() {
-
-      lower_bound <- 0.0
-      .Call(
-        LGBM_BoosterGetLowerBoundValue_R
-        , private$handle
-        , lower_bound
-      )
-      return(lower_bound)
-
-    },
-
-    # Evaluate data on metrics
-    eval = function(data, name, feval = NULL) {
-
-      # Check if dataset is lgb.Dataset
-      if (!lgb.check.r6.class(object = data, name = "lgb.Dataset")) {
-        stop("lgb.Booster.eval: Can only use lgb.Dataset to eval")
-      }
-
-      # Check for identical data
-      data_idx <- 0L
-      if (identical(data, private$train_set)) {
-        data_idx <- 1L
-      } else {
-
-        # Check for validation data
-        if (length(private$valid_sets) > 0L) {
-
-          # Loop through each validation set
-          for (i in seq_along(private$valid_sets)) {
-
-            # Check for identical validation data with training data
-            if (identical(data, private$valid_sets[[i]])) {
-
-              # Found identical data, skip
-              data_idx <- i + 1L
-              break
-
-            }
-
-          }
-
-        }
-
-      }
-
-      # Check if evaluation was not done
-      if (data_idx == 0L) {
-
-        # Add validation data by name
-        self$add_valid(data, name)
-        data_idx <- private$num_dataset
-
-      }
-
-      # Evaluate data
-      return(
-        private$inner_eval(
-          data_name = name
-          , data_idx = data_idx
-          , feval = feval
-        )
-      )
-
-    },
-
-    # Evaluation training data
-    eval_train = function(feval = NULL) {
-      return(private$inner_eval(private$name_train_set, 1L, feval))
-    },
-
-    # Evaluation validation data
-    eval_valid = function(feval = NULL) {
-
-      # Create ret list
-      ret <- list()
-
-      # Check if validation is empty
-      if (length(private$valid_sets) <= 0L) {
-        return(ret)
-      }
-
-      # Loop through each validation set
-      for (i in seq_along(private$valid_sets)) {
-        ret <- append(
-          x = ret
-          , values = private$inner_eval(private$name_valid_sets[[i]], i + 1L, feval)
-        )
-      }
-
-      return(ret)
-
-    },
-
-    # Save model
-    save_model = function(filename, num_iteration = NULL, feature_importance_type = 0L) {
-
-      # Check if number of iteration is non existent
-      if (is.null(num_iteration)) {
-        num_iteration <- self$best_iter
-      }
-
-      # Save booster model
-      .Call(
-        LGBM_BoosterSaveModel_R
-        , private$handle
-        , as.integer(num_iteration)
-        , as.integer(feature_importance_type)
-        , filename
-      )
-
-      return(invisible(self))
-    },
-
-    # Save model to string
-    save_model_to_string = function(num_iteration = NULL, feature_importance_type = 0L) {
-
-      # Check if number of iteration is non existent
-      if (is.null(num_iteration)) {
-        num_iteration <- self$best_iter
-      }
-
-      # Create buffer
-      buf_len <- as.integer(1024L * 1024L)
-      act_len <- 0L
-      buf <- raw(buf_len)
-
-      # Call buffer
-      .Call(
-          LGBM_BoosterSaveModelToString_R
-          , private$handle
-          , as.integer(num_iteration)
-          , as.integer(feature_importance_type)
-          , buf_len
-          , act_len
-          , buf
-      )
-
-      # Check for buffer content
-      if (act_len > buf_len) {
-        buf_len <- act_len
-        buf <- raw(buf_len)
-        .Call(
-          LGBM_BoosterSaveModelToString_R
-          , private$handle
-          , as.integer(num_iteration)
-          , as.integer(feature_importance_type)
-          , buf_len
-          , act_len
-          , buf
-        )
-      }
-
-      return(
-        lgb.encode.char(arr = buf, len = act_len)
-      )
-
-    },
-
-    # Dump model in memory
-    dump_model = function(num_iteration = NULL, feature_importance_type = 0L) {
-
-      # Check if number of iteration is non existent
-      if (is.null(num_iteration)) {
-        num_iteration <- self$best_iter
-      }
-
-      buf_len <- as.integer(1024L * 1024L)
-      act_len <- 0L
-      buf <- raw(buf_len)
-      .Call(
-        LGBM_BoosterDumpModel_R
-        , private$handle
-        , as.integer(num_iteration)
-        , as.integer(feature_importance_type)
-        , buf_len
-        , act_len
-        , buf
-      )
-
-      if (act_len > buf_len) {
-        buf_len <- act_len
-        buf <- raw(buf_len)
-        .Call(
-          LGBM_BoosterDumpModel_R
-          , private$handle
-          , as.integer(num_iteration)
-          , as.integer(feature_importance_type)
-          , buf_len
-          , act_len
-          , buf
-        )
-      }
-
-      return(
-        lgb.encode.char(arr = buf, len = act_len)
-      )
-
-    },
-
-    # Predict on new data
-    predict = function(data,
-                       start_iteration = NULL,
-                       num_iteration = NULL,
-                       rawscore = FALSE,
-                       predleaf = FALSE,
-                       predcontrib = FALSE,
-                       header = FALSE,
-                       reshape = FALSE, ...) {
-
-      # Check if number of iteration is non existent
-      if (is.null(num_iteration)) {
-        num_iteration <- self$best_iter
-      }
-      # Check if start iteration is non existent
-      if (is.null(start_iteration)) {
-        start_iteration <- 0L
-      }
-
-      # Predict on new data
-      predictor <- Predictor$new(private$handle, ...)
-      return(
-        predictor$predict(
-          data = data
-          , start_iteration = start_iteration
-          , num_iteration = num_iteration
-          , rawscore = rawscore
-          , predleaf = predleaf
-          , predcontrib = predcontrib
-          , header = header
-          , reshape = reshape
-        )
-      )
-
-    },
-
-    # Transform into predictor
-    to_predictor = function() {
-      return(Predictor$new(private$handle))
-    },
-
-    # Used for save
-    raw = NA,
-
-    # Save model to temporary file for in-memory saving
-    save = function() {
-
-      # Overwrite model in object
-      self$raw <- self$save_model_to_string(NULL)
-
-      return(invisible(NULL))
-
-    }
-
-  ),
-  private = list(
-    handle = NULL,
-    train_set = NULL,
-    name_train_set = "training",
-    valid_sets = list(),
-    name_valid_sets = list(),
-    predict_buffer = list(),
-    is_predicted_cur_iter = list(),
-    num_class = 1L,
-    num_dataset = 0L,
-    init_predictor = NULL,
-    eval_names = NULL,
-    higher_better_inner_eval = NULL,
-    set_objective_to_none = FALSE,
-    train_set_version = 0L,
-    # Predict data
-    inner_predict = function(idx) {
-
-      # Store data name
-      data_name <- private$name_train_set
-
-      # Check for id bigger than 1
-      if (idx > 1L) {
-        data_name <- private$name_valid_sets[[idx - 1L]]
-      }
-
-      # Check for unknown dataset (over the maximum provided range)
-      if (idx > private$num_dataset) {
-        stop("data_idx should not be greater than num_dataset")
-      }
-
-      # Check for prediction buffer
-      if (is.null(private$predict_buffer[[data_name]])) {
-
-        # Store predictions
-        npred <- 0L
-        .Call(
-          LGBM_BoosterGetNumPredict_R
-          , private$handle
-          , as.integer(idx - 1L)
-          , npred
-        )
-        private$predict_buffer[[data_name]] <- numeric(npred)
-
-      }
-
-      # Check if current iteration was already predicted
-      if (!private$is_predicted_cur_iter[[idx]]) {
-
-        # Use buffer
-        .Call(
-          LGBM_BoosterGetPredict_R
-          , private$handle
-          , as.integer(idx - 1L)
-          , private$predict_buffer[[data_name]]
-        )
-        private$is_predicted_cur_iter[[idx]] <- TRUE
-      }
-
-      return(private$predict_buffer[[data_name]])
-    },
-
-    # Get evaluation information
-    get_eval_info = function() {
-
-      # Check for evaluation names emptiness
-      if (is.null(private$eval_names)) {
-
-        # Get evaluation names
-        buf_len <- as.integer(1024L * 1024L)
-        act_len <- 0L
-        buf <- raw(buf_len)
-        .Call(
-          LGBM_BoosterGetEvalNames_R
-          , private$handle
-          , buf_len
-          , act_len
-          , buf
-        )
-        if (act_len > buf_len) {
-          buf_len <- act_len
-          buf <- raw(buf_len)
-          .Call(
-            LGBM_BoosterGetEvalNames_R
-            , private$handle
-            , buf_len
-            , act_len
-            , buf
-          )
-        }
-        names <- lgb.encode.char(arr = buf, len = act_len)
-
-        # Check names' length
-        if (nchar(names) > 0L) {
-
-          # Parse and store privately names
-          names <- strsplit(names, "\t")[[1L]]
-          private$eval_names <- names
-
-          # some metrics don't map cleanly to metric names, for example "ndcg@1" is just the
-          # ndcg metric evaluated at the first "query result" in learning-to-rank
-          metric_names <- gsub("@.*", "", names)
-          private$higher_better_inner_eval <- .METRICS_HIGHER_BETTER()[metric_names]
-
-        }
-
-      }
-
-      return(private$eval_names)
-
-    },
-
-    # Perform inner evaluation
-    inner_eval = function(data_name, data_idx, feval = NULL) {
-
-      # Check for unknown dataset (over the maximum provided range)
-      if (data_idx > private$num_dataset) {
-        stop("data_idx should not be greater than num_dataset")
-      }
-
-      # Get evaluation information
-      private$get_eval_info()
-
-      # Prepare return
-      ret <- list()
-
-      # Check evaluation names existence
-      if (length(private$eval_names) > 0L) {
-
-        # Create evaluation values
-        tmp_vals <- numeric(length(private$eval_names))
-        .Call(
-          LGBM_BoosterGetEval_R
-          , private$handle
-          , as.integer(data_idx - 1L)
-          , tmp_vals
-        )
-
-        # Loop through all evaluation names
-        for (i in seq_along(private$eval_names)) {
-
-          # Store evaluation and append to return
-          res <- list()
-          res$data_name <- data_name
-          res$name <- private$eval_names[i]
-          res$value <- tmp_vals[i]
-          res$higher_better <- private$higher_better_inner_eval[i]
-          ret <- append(ret, list(res))
-
-        }
-
-      }
-
-      # Check if there are evaluation metrics
-      if (!is.null(feval)) {
-
-        # Check if evaluation metric is a function
-        if (!is.function(feval)) {
-          stop("lgb.Booster.eval: feval should be a function")
-        }
-
-        # Prepare data
-        data <- private$train_set
-
-        # Check if data to assess is existing differently
-        if (data_idx > 1L) {
-          data <- private$valid_sets[[data_idx - 1L]]
-        }
-
-        # Perform function evaluation
-        res <- feval(private$inner_predict(data_idx), data)
-
-        # Check for name correctness
-        if (is.null(res$name) || is.null(res$value) ||  is.null(res$higher_better)) {
-          stop("lgb.Booster.eval: custom eval function should return a
-            list with attribute (name, value, higher_better)");
-        }
-
-        # Append names and evaluation
-        res$data_name <- data_name
-        ret <- append(ret, list(res))
-      }
-
-      return(ret)
-
-    }
-
-  )
-)
-
-#' @name predict.lgb.Booster
-#' @title Predict method for LightGBM model
-#' @description Predicted values based on class \code{lgb.Booster}
-#' @param object Object of class \code{lgb.Booster}
-#' @param data a \code{matrix} object, a \code{dgCMatrix} object or a character representing a filename
-#' @param start_iteration int or None, optional (default=None)
-#'                        Start index of the iteration to predict.
-#'                        If None or <= 0, starts from the first iteration.
-#' @param num_iteration int or None, optional (default=None)
-#'                      Limit number of iterations in the prediction.
-#'                      If None, if the best iteration exists and start_iteration is None or <= 0, the
-#'                      best iteration is used; otherwise, all iterations from start_iteration are used.
-#'                      If <= 0, all iterations from start_iteration are used (no limits).
-#' @param rawscore whether the prediction should be returned in the for of original untransformed
-#'                 sum of predictions from boosting iterations' results. E.g., setting \code{rawscore=TRUE}
-#'                 for logistic regression would result in predictions for log-odds instead of probabilities.
-#' @param predleaf whether predict leaf index instead.
-#' @param predcontrib return per-feature contributions for each record.
-#' @param header only used for prediction for text file. True if text file has header
-#' @param reshape whether to reshape the vector of predictions to a matrix form when there are several
-#'                prediction outputs per case.
-#' @param ... Additional named arguments passed to the \code{predict()} method of
-#'            the \code{lgb.Booster} object passed to \code{object}.
-#' @return For regression or binary classification, it returns a vector of length \code{nrows(data)}.
-#'         For multiclass classification, either a \code{num_class * nrows(data)} vector or
-#'         a \code{(nrows(data), num_class)} dimension matrix is returned, depending on
-#'         the \code{reshape} value.
-#'
-#'         When \code{predleaf = TRUE}, the output is a matrix object with the
-#'         number of columns corresponding to the number of trees.
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data(agaricus.test, package = "lightgbm")
-#' test <- agaricus.test
-#' dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-#' params <- list(objective = "regression", metric = "l2")
-#' valids <- list(test = dtest)
-#' model <- lgb.train(
-#'   params = params
-#'   , data = dtrain
-#'   , nrounds = 5L
-#'   , valids = valids
-#'   , min_data = 1L
-#'   , learning_rate = 1.0
-#' )
-#' preds <- predict(model, test$data)
-#' }
-#' @export
-predict.lgb.Booster <- function(object,
-                                data,
-                                start_iteration = NULL,
-                                num_iteration = NULL,
-                                rawscore = FALSE,
-                                predleaf = FALSE,
-                                predcontrib = FALSE,
-                                header = FALSE,
-                                reshape = FALSE,
-                                ...) {
-
-  if (!lgb.is.Booster(x = object)) {
-    stop("predict.lgb.Booster: object should be an ", sQuote("lgb.Booster"))
-  }
-
-  # Return booster predictions
-  return(
-    object$predict(
-      data = data
-      , start_iteration = start_iteration
-      , num_iteration = num_iteration
-      , rawscore = rawscore
-      , predleaf =  predleaf
-      , predcontrib =  predcontrib
-      , header = header
-      , reshape = reshape
-      , ...
-    )
-  )
-}
-
-#' @name lgb.load
-#' @title Load LightGBM model
-#' @description  Load LightGBM takes in either a file path or model string.
-#'               If both are provided, Load will default to loading from file
-#' @param filename path of model file
-#' @param model_str a str containing the model
-#'
-#' @return lgb.Booster
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data(agaricus.test, package = "lightgbm")
-#' test <- agaricus.test
-#' dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-#' params <- list(objective = "regression", metric = "l2")
-#' valids <- list(test = dtest)
-#' model <- lgb.train(
-#'   params = params
-#'   , data = dtrain
-#'   , nrounds = 5L
-#'   , valids = valids
-#'   , min_data = 1L
-#'   , learning_rate = 1.0
-#'   , early_stopping_rounds = 3L
-#' )
-#' model_file <- tempfile(fileext = ".txt")
-#' lgb.save(model, model_file)
-#' load_booster <- lgb.load(filename = model_file)
-#' model_string <- model$save_model_to_string(NULL) # saves best iteration
-#' load_booster_from_str <- lgb.load(model_str = model_string)
-#' }
-#' @export
-lgb.load <- function(filename = NULL, model_str = NULL) {
-
-  filename_provided <- !is.null(filename)
-  model_str_provided <- !is.null(model_str)
-
-  if (filename_provided) {
-    if (!is.character(filename)) {
-      stop("lgb.load: filename should be character")
-    }
-    if (!file.exists(filename)) {
-      stop(sprintf("lgb.load: file '%s' passed to filename does not exist", filename))
-    }
-    return(invisible(Booster$new(modelfile = filename)))
-  }
-
-  if (model_str_provided) {
-    if (!is.character(model_str)) {
-      stop("lgb.load: model_str should be character")
-    }
-    return(invisible(Booster$new(model_str = model_str)))
-  }
-
-  stop("lgb.load: either filename or model_str must be given")
-}
-
-#' @name lgb.save
-#' @title Save LightGBM model
-#' @description Save LightGBM model
-#' @param booster Object of class \code{lgb.Booster}
-#' @param filename saved filename
-#' @param num_iteration number of iteration want to predict with, NULL or <= 0 means use best iteration
-#'
-#' @return lgb.Booster
-#'
-#' @examples
-#' \donttest{
-#' library(lightgbm)
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data(agaricus.test, package = "lightgbm")
-#' test <- agaricus.test
-#' dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-#' params <- list(objective = "regression", metric = "l2")
-#' valids <- list(test = dtest)
-#' model <- lgb.train(
-#'   params = params
-#'   , data = dtrain
-#'   , nrounds = 10L
-#'   , valids = valids
-#'   , min_data = 1L
-#'   , learning_rate = 1.0
-#'   , early_stopping_rounds = 5L
-#' )
-#' lgb.save(model, tempfile(fileext = ".txt"))
-#' }
-#' @export
-lgb.save <- function(booster, filename, num_iteration = NULL) {
-
-  if (!lgb.is.Booster(x = booster)) {
-    stop("lgb.save: booster should be an ", sQuote("lgb.Booster"))
-  }
-
-  if (!(is.character(filename) && length(filename) == 1L)) {
-    stop("lgb.save: filename should be a string")
-  }
-
-  # Store booster
-  return(
-    invisible(booster$save_model(
-      filename = filename
-      , num_iteration = num_iteration
-    ))
-  )
-
-}
-
-#' @name lgb.dump
-#' @title Dump LightGBM model to json
-#' @description Dump LightGBM model to json
-#' @param booster Object of class \code{lgb.Booster}
-#' @param num_iteration number of iteration want to predict with, NULL or <= 0 means use best iteration
-#'
-#' @return json format of model
-#'
-#' @examples
-#' \donttest{
-#' library(lightgbm)
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data(agaricus.test, package = "lightgbm")
-#' test <- agaricus.test
-#' dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-#' params <- list(objective = "regression", metric = "l2")
-#' valids <- list(test = dtest)
-#' model <- lgb.train(
-#'   params = params
-#'   , data = dtrain
-#'   , nrounds = 10L
-#'   , valids = valids
-#'   , min_data = 1L
-#'   , learning_rate = 1.0
-#'   , early_stopping_rounds = 5L
-#' )
-#' json_model <- lgb.dump(model)
-#' }
-#' @export
-lgb.dump <- function(booster, num_iteration = NULL) {
-
-  if (!lgb.is.Booster(x = booster)) {
-    stop("lgb.save: booster should be an ", sQuote("lgb.Booster"))
-  }
-
-  # Return booster at requested iteration
-  return(booster$dump_model(num_iteration =  num_iteration))
-
-}
-
-#' @name lgb.get.eval.result
-#' @title Get record evaluation result from booster
-#' @description Given a \code{lgb.Booster}, return evaluation results for a
-#'              particular metric on a particular dataset.
-#' @param booster Object of class \code{lgb.Booster}
-#' @param data_name Name of the dataset to return evaluation results for.
-#' @param eval_name Name of the evaluation metric to return results for.
-#' @param iters An integer vector of iterations you want to get evaluation results for. If NULL
-#'              (the default), evaluation results for all iterations will be returned.
-#' @param is_err TRUE will return evaluation error instead
-#'
-#' @return numeric vector of evaluation result
-#'
-#' @examples
-#' \donttest{
-#' # train a regression model
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data(agaricus.test, package = "lightgbm")
-#' test <- agaricus.test
-#' dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-#' params <- list(objective = "regression", metric = "l2")
-#' valids <- list(test = dtest)
-#' model <- lgb.train(
-#'   params = params
-#'   , data = dtrain
-#'   , nrounds = 5L
-#'   , valids = valids
-#'   , min_data = 1L
-#'   , learning_rate = 1.0
-#' )
-#'
-#' # Examine valid data_name values
-#' print(setdiff(names(model$record_evals), "start_iter"))
-#'
-#' # Examine valid eval_name values for dataset "test"
-#' print(names(model$record_evals[["test"]]))
-#'
-#' # Get L2 values for "test" dataset
-#' lgb.get.eval.result(model, "test", "l2")
-#' }
-#' @export
-lgb.get.eval.result <- function(booster, data_name, eval_name, iters = NULL, is_err = FALSE) {
-
-  # Check if booster is booster
-  if (!lgb.is.Booster(x = booster)) {
-    stop("lgb.get.eval.result: Can only use ", sQuote("lgb.Booster"), " to get eval result")
-  }
-
-  # Check if data and evaluation name are characters or not
-  if (!is.character(data_name) || !is.character(eval_name)) {
-    stop("lgb.get.eval.result: data_name and eval_name should be characters")
-  }
-
-  # NOTE: "start_iter" exists in booster$record_evals but is not a valid data_name
-  data_names <- setdiff(names(booster$record_evals), "start_iter")
-  if (!(data_name %in% data_names)) {
-    stop(paste0(
-      "lgb.get.eval.result: data_name "
-      , shQuote(data_name)
-      , " not found. Only the following datasets exist in record evals: ["
-      , paste(data_names, collapse = ", ")
-      , "]"
-    ))
-  }
-
-  # Check if evaluation result is existing
-  eval_names <- names(booster$record_evals[[data_name]])
-  if (!(eval_name %in% eval_names)) {
-    stop(paste0(
-      "lgb.get.eval.result: eval_name "
-      , shQuote(eval_name)
-      , " not found. Only the following eval_names exist for dataset "
-      , shQuote(data_name)
-      , ": ["
-      , paste(eval_names, collapse = ", ")
-      , "]"
-    ))
-    stop("lgb.get.eval.result: wrong eval name")
-  }
-
-  result <- booster$record_evals[[data_name]][[eval_name]][[.EVAL_KEY()]]
-
-  # Check if error is requested
-  if (is_err) {
-    result <- booster$record_evals[[data_name]][[eval_name]][[.EVAL_ERR_KEY()]]
-  }
-
-  # Check if iteration is non existant
-  if (is.null(iters)) {
-    return(as.numeric(result))
-  }
-
-  # Parse iteration and booster delta
-  iters <- as.integer(iters)
-  delta <- booster$record_evals$start_iter - 1.0
-  iters <- iters - delta
-
-  # Return requested result
-  return(as.numeric(result[iters]))
-}
diff --git a/R-package/R/lgb.Dataset.R b/R-package/R/lgb.Dataset.R
deleted file mode 100644
index 70c9f09f4..000000000
--- a/R-package/R/lgb.Dataset.R
+++ /dev/null
@@ -1,1214 +0,0 @@
-#' @importFrom methods is
-#' @importFrom R6 R6Class
-Dataset <- R6::R6Class(
-
-  classname = "lgb.Dataset",
-  cloneable = FALSE,
-  public = list(
-
-    # Finalize will free up the handles
-    finalize = function() {
-
-      # Check the need for freeing handle
-      if (!lgb.is.null.handle(x = private$handle)) {
-
-        # Freeing up handle
-        .Call(
-          LGBM_DatasetFree_R
-          , private$handle
-        )
-        private$handle <- NULL
-
-      }
-
-      return(invisible(NULL))
-
-    },
-
-    # Initialize will create a starter dataset
-    initialize = function(data,
-                          params = list(),
-                          reference = NULL,
-                          colnames = NULL,
-                          categorical_feature = NULL,
-                          predictor = NULL,
-                          free_raw_data = TRUE,
-                          used_indices = NULL,
-                          info = list(),
-                          ...) {
-
-      # validate inputs early to avoid unnecessary computation
-      if (!(is.null(reference) || lgb.check.r6.class(object = reference, name = "lgb.Dataset"))) {
-          stop("lgb.Dataset: If provided, reference must be a ", sQuote("lgb.Dataset"))
-      }
-      if (!(is.null(predictor) || lgb.check.r6.class(object = predictor, name = "lgb.Predictor"))) {
-          stop("lgb.Dataset: If provided, predictor must be a ", sQuote("lgb.Predictor"))
-      }
-
-      # Check for additional parameters
-      additional_params <- list(...)
-
-      # Create known attributes list
-      INFO_KEYS <- c("label", "weight", "init_score", "group")
-
-      # Check if attribute key is in the known attribute list
-      for (key in names(additional_params)) {
-
-        # Key existing
-        if (key %in% INFO_KEYS) {
-
-          # Store as info
-          info[[key]] <- additional_params[[key]]
-
-        } else {
-
-          # Store as param
-          params[[key]] <- additional_params[[key]]
-
-        }
-
-      }
-
-      # Check for matrix format
-      if (is.matrix(data)) {
-        # Check whether matrix is the correct type first ("double")
-        if (storage.mode(data) != "double") {
-          storage.mode(data) <- "double"
-        }
-      }
-
-      # Setup private attributes
-      private$raw_data <- data
-      private$params <- params
-      private$reference <- reference
-      private$colnames <- colnames
-
-      private$categorical_feature <- categorical_feature
-      private$predictor <- predictor
-      private$free_raw_data <- free_raw_data
-      private$used_indices <- sort(used_indices, decreasing = FALSE)
-      private$info <- info
-      private$version <- 0L
-
-      return(invisible(NULL))
-
-    },
-
-    create_valid = function(data,
-                            info = list(),
-                            ...) {
-
-      # Create new dataset
-      ret <- Dataset$new(
-        data = data
-        , params = private$params
-        , reference = self
-        , colnames = private$colnames
-        , categorical_feature = private$categorical_feature
-        , predictor = private$predictor
-        , free_raw_data = private$free_raw_data
-        , used_indices = NULL
-        , info = info
-        , ...
-      )
-
-      return(invisible(ret))
-
-    },
-
-    # Dataset constructor
-    construct = function() {
-
-      # Check for handle null
-      if (!lgb.is.null.handle(x = private$handle)) {
-        return(invisible(self))
-      }
-
-      # Get feature names
-      cnames <- NULL
-      if (is.matrix(private$raw_data) || methods::is(private$raw_data, "dgCMatrix")) {
-        cnames <- colnames(private$raw_data)
-      }
-
-      # set feature names if they do not exist
-      if (is.null(private$colnames) && !is.null(cnames)) {
-        private$colnames <- as.character(cnames)
-      }
-
-      # Get categorical feature index
-      if (!is.null(private$categorical_feature)) {
-
-        # Check for character name
-        if (is.character(private$categorical_feature)) {
-
-            cate_indices <- as.list(match(private$categorical_feature, private$colnames) - 1L)
-
-            # Provided indices, but some indices are missing?
-            if (sum(is.na(cate_indices)) > 0L) {
-              stop(
-                "lgb.self.get.handle: supplied an unknown feature in categorical_feature: "
-                , sQuote(private$categorical_feature[is.na(cate_indices)])
-              )
-            }
-
-          } else {
-
-            # Check if more categorical features were output over the feature space
-            if (max(private$categorical_feature) > length(private$colnames)) {
-              stop(
-                "lgb.self.get.handle: supplied a too large value in categorical_feature: "
-                , max(private$categorical_feature)
-                , " but only "
-                , length(private$colnames)
-                , " features"
-              )
-            }
-
-            # Store indices as [0, n-1] indexed instead of [1, n] indexed
-            cate_indices <- as.list(private$categorical_feature - 1L)
-
-          }
-
-        # Store indices for categorical features
-        private$params$categorical_feature <- cate_indices
-
-      }
-
-      # Check has header or not
-      has_header <- FALSE
-      if (!is.null(private$params$has_header) || !is.null(private$params$header)) {
-        params_has_header <- tolower(as.character(private$params$has_header)) == "true"
-        params_header <- tolower(as.character(private$params$header)) == "true"
-        if (params_has_header || params_header) {
-          has_header <- TRUE
-        }
-      }
-
-      # Generate parameter str
-      params_str <- lgb.params2str(params = private$params)
-
-      # Get handle of reference dataset
-      ref_handle <- NULL
-      if (!is.null(private$reference)) {
-        ref_handle <- private$reference$.__enclos_env__$private$get_handle()
-      }
-      handle <- lgb.null.handle()
-
-      # Not subsetting
-      if (is.null(private$used_indices)) {
-
-        # Are we using a data file?
-        if (is.character(private$raw_data)) {
-
-          .Call(
-            LGBM_DatasetCreateFromFile_R
-            , private$raw_data
-            , params_str
-            , ref_handle
-            , handle
-          )
-
-        } else if (is.matrix(private$raw_data)) {
-
-          # Are we using a matrix?
-          .Call(
-            LGBM_DatasetCreateFromMat_R
-            , private$raw_data
-            , nrow(private$raw_data)
-            , ncol(private$raw_data)
-            , params_str
-            , ref_handle
-            , handle
-          )
-
-        } else if (methods::is(private$raw_data, "dgCMatrix")) {
-          if (length(private$raw_data@p) > 2147483647L) {
-            stop("Cannot support large CSC matrix")
-          }
-          # Are we using a dgCMatrix (sparsed matrix column compressed)
-          .Call(
-            LGBM_DatasetCreateFromCSC_R
-            , private$raw_data@p
-            , private$raw_data@i
-            , private$raw_data@x
-            , length(private$raw_data@p)
-            , length(private$raw_data@x)
-            , nrow(private$raw_data)
-            , params_str
-            , ref_handle
-            , handle
-          )
-
-        } else {
-
-          # Unknown data type
-          stop(
-            "lgb.Dataset.construct: does not support constructing from "
-            , sQuote(class(private$raw_data))
-          )
-
-        }
-
-      } else {
-
-        # Reference is empty
-        if (is.null(private$reference)) {
-          stop("lgb.Dataset.construct: reference cannot be NULL for constructing data subset")
-        }
-
-        # Construct subset
-        .Call(
-          LGBM_DatasetGetSubset_R
-          , ref_handle
-          , c(private$used_indices) # Adding c() fixes issue in R v3.5
-          , length(private$used_indices)
-          , params_str
-          , handle
-        )
-
-      }
-      if (lgb.is.null.handle(x = handle)) {
-        stop("lgb.Dataset.construct: cannot create Dataset handle")
-      }
-      # Setup class and private type
-      class(handle) <- "lgb.Dataset.handle"
-      private$handle <- handle
-
-      # Set feature names
-      if (!is.null(private$colnames)) {
-        self$set_colnames(colnames = private$colnames)
-      }
-
-      # Load init score if requested
-      if (!is.null(private$predictor) && is.null(private$used_indices)) {
-
-        # Setup initial scores
-        init_score <- private$predictor$predict(
-          data = private$raw_data
-          , rawscore = TRUE
-          , reshape = TRUE
-        )
-
-        # Not needed to transpose, for is col_marjor
-        init_score <- as.vector(init_score)
-        private$info$init_score <- init_score
-
-      }
-
-      # Should we free raw data?
-      if (isTRUE(private$free_raw_data)) {
-        private$raw_data <- NULL
-      }
-
-      # Get private information
-      if (length(private$info) > 0L) {
-
-        # Set infos
-        for (i in seq_along(private$info)) {
-
-          p <- private$info[i]
-          self$setinfo(name = names(p), info = p[[1L]])
-
-        }
-
-      }
-
-      # Get label information existence
-      if (is.null(self$getinfo(name = "label"))) {
-        stop("lgb.Dataset.construct: label should be set")
-      }
-
-      return(invisible(self))
-
-    },
-
-    # Dimension function
-    dim = function() {
-
-      # Check for handle
-      if (!lgb.is.null.handle(x = private$handle)) {
-
-        num_row <- 0L
-        num_col <- 0L
-
-        # Get numeric data and numeric features
-        .Call(
-          LGBM_DatasetGetNumData_R
-          , private$handle
-          , num_row
-        )
-        .Call(
-          LGBM_DatasetGetNumFeature_R
-          , private$handle
-          , num_col
-        )
-        return(
-          c(num_row, num_col)
-        )
-
-      } else if (is.matrix(private$raw_data) || methods::is(private$raw_data, "dgCMatrix")) {
-
-        # Check if dgCMatrix (sparse matrix column compressed)
-        # NOTE: requires Matrix package
-        return(dim(private$raw_data))
-
-      } else {
-
-        # Trying to work with unknown dimensions is not possible
-        stop(
-          "dim: cannot get dimensions before dataset has been constructed, "
-          , "please call lgb.Dataset.construct explicitly"
-        )
-
-      }
-
-    },
-
-    # Get column names
-    get_colnames = function() {
-
-      # Check for handle
-      if (!lgb.is.null.handle(x = private$handle)) {
-
-        # Get feature names and write them
-        buf_len <- as.integer(1024L * 1024L)
-        act_len <- 0L
-        buf <- raw(buf_len)
-        .Call(
-          LGBM_DatasetGetFeatureNames_R
-          , private$handle
-          , buf_len
-          , act_len
-          , buf
-        )
-        if (act_len > buf_len) {
-          buf_len <- act_len
-          buf <- raw(buf_len)
-          .Call(
-            LGBM_DatasetGetFeatureNames_R
-            , private$handle
-            , buf_len
-            , act_len
-            , buf
-          )
-        }
-        cnames <- lgb.encode.char(arr = buf, len = act_len)
-        private$colnames <- as.character(base::strsplit(cnames, "\t")[[1L]])
-        return(private$colnames)
-
-      } else if (is.matrix(private$raw_data) || methods::is(private$raw_data, "dgCMatrix")) {
-
-        # Check if dgCMatrix (sparse matrix column compressed)
-        return(colnames(private$raw_data))
-
-      } else {
-
-        # Trying to work with unknown dimensions is not possible
-        stop(
-          "dim: cannot get dimensions before dataset has been constructed, please call "
-          , "lgb.Dataset.construct explicitly"
-        )
-
-      }
-
-    },
-
-    # Set column names
-    set_colnames = function(colnames) {
-
-      # Check column names non-existence
-      if (is.null(colnames)) {
-        return(invisible(self))
-      }
-
-      # Check empty column names
-      colnames <- as.character(colnames)
-      if (length(colnames) == 0L) {
-        return(invisible(self))
-      }
-
-      # Write column names
-      private$colnames <- colnames
-      if (!lgb.is.null.handle(x = private$handle)) {
-
-        # Merge names with tab separation
-        merged_name <- paste0(as.list(private$colnames), collapse = "\t")
-        .Call(
-          LGBM_DatasetSetFeatureNames_R
-          , private$handle
-          , merged_name
-        )
-
-      }
-
-      return(invisible(self))
-
-    },
-
-    # Get information
-    getinfo = function(name) {
-
-      # Create known attributes list
-      INFONAMES <- c("label", "weight", "init_score", "group")
-
-      # Check if attribute key is in the known attribute list
-      if (!is.character(name) || length(name) != 1L || !name %in% INFONAMES) {
-        stop("getinfo: name must one of the following: ", paste0(sQuote(INFONAMES), collapse = ", "))
-      }
-
-      # Check for info name and handle
-      if (is.null(private$info[[name]])) {
-
-        if (lgb.is.null.handle(x = private$handle)) {
-          stop("Cannot perform getinfo before constructing Dataset.")
-        }
-
-        # Get field size of info
-        info_len <- 0L
-        .Call(
-          LGBM_DatasetGetFieldSize_R
-          , private$handle
-          , name
-          , info_len
-        )
-
-        # Check if info is not empty
-        if (info_len > 0L) {
-
-          # Get back fields
-          ret <- NULL
-          ret <- if (name == "group") {
-            integer(info_len) # Integer
-          } else {
-            numeric(info_len) # Numeric
-          }
-
-          .Call(
-            LGBM_DatasetGetField_R
-            , private$handle
-            , name
-            , ret
-          )
-
-          private$info[[name]] <- ret
-
-        }
-      }
-
-      return(private$info[[name]])
-
-    },
-
-    # Set information
-    setinfo = function(name, info) {
-
-      # Create known attributes list
-      INFONAMES <- c("label", "weight", "init_score", "group")
-
-      # Check if attribute key is in the known attribute list
-      if (!is.character(name) || length(name) != 1L || !name %in% INFONAMES) {
-        stop("setinfo: name must one of the following: ", paste0(sQuote(INFONAMES), collapse = ", "))
-      }
-
-      # Check for type of information
-      info <- if (name == "group") {
-        as.integer(info) # Integer
-      } else {
-        as.numeric(info) # Numeric
-      }
-
-      # Store information privately
-      private$info[[name]] <- info
-
-      if (!lgb.is.null.handle(x = private$handle) && !is.null(info)) {
-
-        if (length(info) > 0L) {
-
-          .Call(
-            LGBM_DatasetSetField_R
-            , private$handle
-            , name
-            , info
-            , length(info)
-          )
-
-          private$version <- private$version + 1L
-
-        }
-
-      }
-
-      return(invisible(self))
-
-    },
-
-    # Slice dataset
-    slice = function(idxset, ...) {
-
-      # Perform slicing
-      return(
-        Dataset$new(
-          data = NULL
-          , params = private$params
-          , reference = self
-          , colnames = private$colnames
-          , categorical_feature = private$categorical_feature
-          , predictor = private$predictor
-          , free_raw_data = private$free_raw_data
-          , used_indices = sort(idxset, decreasing = FALSE)
-          , info = NULL
-          , ...
-        )
-      )
-
-    },
-
-    # [description] Update Dataset parameters. If it has not been constructed yet,
-    #               this operation just happens on the R side (updating private$params).
-    #               If it has been constructed, parameters will be updated on the C++ side.
-    update_params = function(params) {
-      if (length(params) == 0L) {
-        return(invisible(self))
-      }
-      if (lgb.is.null.handle(x = private$handle)) {
-        private$params <- modifyList(private$params, params)
-      } else {
-        tryCatch({
-          .Call(
-            LGBM_DatasetUpdateParamChecking_R
-            , lgb.params2str(params = private$params)
-            , lgb.params2str(params = params)
-          )
-        }, error = function(e) {
-          # If updating failed but raw data is not available, raise an error because
-          # achieving what the user asked for is not possible
-          if (is.null(private$raw_data)) {
-            stop(e)
-          }
-
-          # If updating failed but raw data is available, modify the params
-          # on the R side and re-set ("deconstruct") the Dataset
-          private$params <- modifyList(private$params, params)
-          self$finalize()
-        })
-      }
-      return(invisible(self))
-
-    },
-
-    get_params = function() {
-      dataset_params <- unname(unlist(.DATASET_PARAMETERS()))
-      ret <- list()
-      for (param_key in names(private$params)) {
-        if (param_key %in% dataset_params) {
-          ret[[param_key]] <- private$params[[param_key]]
-        }
-      }
-      return(ret)
-    },
-
-    # Set categorical feature parameter
-    set_categorical_feature = function(categorical_feature) {
-
-      # Check for identical input
-      if (identical(private$categorical_feature, categorical_feature)) {
-        return(invisible(self))
-      }
-
-      # Check for empty data
-      if (is.null(private$raw_data)) {
-        stop("set_categorical_feature: cannot set categorical feature after freeing raw data,
-          please set ", sQuote("free_raw_data = FALSE"), " when you construct lgb.Dataset")
-      }
-
-      # Overwrite categorical features
-      private$categorical_feature <- categorical_feature
-
-      # Finalize and return self
-      self$finalize()
-      return(invisible(self))
-
-    },
-
-    # Set reference
-    set_reference = function(reference) {
-
-      # Set known references
-      self$set_categorical_feature(categorical_feature = reference$.__enclos_env__$private$categorical_feature)
-      self$set_colnames(colnames = reference$get_colnames())
-      private$set_predictor(predictor = reference$.__enclos_env__$private$predictor)
-
-      # Check for identical references
-      if (identical(private$reference, reference)) {
-        return(invisible(self))
-      }
-
-      # Check for empty data
-      if (is.null(private$raw_data)) {
-
-        stop("set_reference: cannot set reference after freeing raw data,
-          please set ", sQuote("free_raw_data = FALSE"), " when you construct lgb.Dataset")
-
-      }
-
-      # Check for non-existing reference
-      if (!is.null(reference)) {
-
-        # Reference is unknown
-        if (!lgb.check.r6.class(object = reference, name = "lgb.Dataset")) {
-          stop("set_reference: Can only use lgb.Dataset as a reference")
-        }
-
-      }
-
-      # Store reference
-      private$reference <- reference
-
-      # Finalize and return self
-      self$finalize()
-      return(invisible(self))
-
-    },
-
-    # Save binary model
-    save_binary = function(fname) {
-
-      # Store binary data
-      self$construct()
-      .Call(
-        LGBM_DatasetSaveBinary_R
-        , private$handle
-        , fname
-      )
-      return(invisible(self))
-    }
-
-  ),
-  private = list(
-    handle = NULL,
-    raw_data = NULL,
-    params = list(),
-    reference = NULL,
-    colnames = NULL,
-    categorical_feature = NULL,
-    predictor = NULL,
-    free_raw_data = TRUE,
-    used_indices = NULL,
-    info = NULL,
-    version = 0L,
-
-    # Get handle
-    get_handle = function() {
-
-      # Get handle and construct if needed
-      if (lgb.is.null.handle(x = private$handle)) {
-        self$construct()
-      }
-      return(private$handle)
-
-    },
-
-    # Set predictor
-    set_predictor = function(predictor) {
-
-      if (identical(private$predictor, predictor)) {
-        return(invisible(self))
-      }
-
-      # Check for empty data
-      if (is.null(private$raw_data)) {
-        stop("set_predictor: cannot set predictor after free raw data,
-          please set ", sQuote("free_raw_data = FALSE"), " when you construct lgb.Dataset")
-      }
-
-      # Check for empty predictor
-      if (!is.null(predictor)) {
-
-        # Predictor is unknown
-        if (!lgb.check.r6.class(object = predictor, name = "lgb.Predictor")) {
-          stop("set_predictor: Can only use lgb.Predictor as predictor")
-        }
-
-      }
-
-      # Store predictor
-      private$predictor <- predictor
-
-      # Finalize and return self
-      self$finalize()
-      return(invisible(self))
-
-    }
-
-  )
-)
-
-#' @title Construct \code{lgb.Dataset} object
-#' @description Construct \code{lgb.Dataset} object from dense matrix, sparse matrix
-#'              or local file (that was created previously by saving an \code{lgb.Dataset}).
-#' @param data a \code{matrix} object, a \code{dgCMatrix} object or a character representing a filename
-#' @param params a list of parameters. See
-#'               \href{https://lightgbm.readthedocs.io/en/latest/Parameters.html#dataset-parameters}{
-#'               The "Dataset Parameters" section of the documentation} for a list of parameters
-#'               and valid values.
-#' @param reference reference dataset. When LightGBM creates a Dataset, it does some preprocessing like binning
-#'                  continuous features into histograms. If you want to apply the same bin boundaries from an existing
-#'                  dataset to new \code{data}, pass that existing Dataset to this argument.
-#' @param colnames names of columns
-#' @param categorical_feature categorical features. This can either be a character vector of feature
-#'                            names or an integer vector with the indices of the features (e.g.
-#'                            \code{c(1L, 10L)} to say "the first and tenth columns").
-#' @param free_raw_data LightGBM constructs its data format, called a "Dataset", from tabular data.
-#'                      By default, that Dataset object on the R side does not keep a copy of the raw data.
-#'                      This reduces LightGBM's memory consumption, but it means that the Dataset object
-#'                      cannot be changed after it has been constructed. If you'd prefer to be able to
-#'                      change the Dataset object after construction, set \code{free_raw_data = FALSE}.
-#' @param info a list of information of the \code{lgb.Dataset} object
-#' @param ... other information to pass to \code{info} or parameters pass to \code{params}
-#'
-#' @return constructed dataset
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data_file <- tempfile(fileext = ".data")
-#' lgb.Dataset.save(dtrain, data_file)
-#' dtrain <- lgb.Dataset(data_file)
-#' lgb.Dataset.construct(dtrain)
-#' }
-#' @export
-lgb.Dataset <- function(data,
-                        params = list(),
-                        reference = NULL,
-                        colnames = NULL,
-                        categorical_feature = NULL,
-                        free_raw_data = TRUE,
-                        info = list(),
-                        ...) {
-
-  # Create new dataset
-  return(
-    invisible(Dataset$new(
-      data = data
-      , params = params
-      , reference = reference
-      , colnames = colnames
-      , categorical_feature = categorical_feature
-      , predictor = NULL
-      , free_raw_data = free_raw_data
-      , used_indices = NULL
-      , info = info
-      , ...
-    ))
-  )
-
-}
-
-#' @name lgb.Dataset.create.valid
-#' @title Construct validation data
-#' @description Construct validation data according to training data
-#' @param dataset \code{lgb.Dataset} object, training data
-#' @param data a \code{matrix} object, a \code{dgCMatrix} object or a character representing a filename
-#' @param info a list of information of the \code{lgb.Dataset} object
-#' @param ... other information to pass to \code{info}.
-#'
-#' @return constructed dataset
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data(agaricus.test, package = "lightgbm")
-#' test <- agaricus.test
-#' dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-#' }
-#' @export
-lgb.Dataset.create.valid <- function(dataset, data, info = list(), ...) {
-
-  # Check if dataset is not a dataset
-  if (!lgb.is.Dataset(x = dataset)) {
-    stop("lgb.Dataset.create.valid: input data should be an lgb.Dataset object")
-  }
-
-  # Create validation dataset
-  return(invisible(dataset$create_valid(data = data, info = info, ...)))
-
-}
-
-#' @name lgb.Dataset.construct
-#' @title Construct Dataset explicitly
-#' @description Construct Dataset explicitly
-#' @param dataset Object of class \code{lgb.Dataset}
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' lgb.Dataset.construct(dtrain)
-#' }
-#' @return constructed dataset
-#' @export
-lgb.Dataset.construct <- function(dataset) {
-
-  # Check if dataset is not a dataset
-  if (!lgb.is.Dataset(x = dataset)) {
-    stop("lgb.Dataset.construct: input data should be an lgb.Dataset object")
-  }
-
-  # Construct the dataset
-  return(invisible(dataset$construct()))
-
-}
-
-#' @title Dimensions of an \code{lgb.Dataset}
-#' @description Returns a vector of numbers of rows and of columns in an \code{lgb.Dataset}.
-#' @param x Object of class \code{lgb.Dataset}
-#' @param ... other parameters
-#'
-#' @return a vector of numbers of rows and of columns
-#'
-#' @details
-#' Note: since \code{nrow} and \code{ncol} internally use \code{dim}, they can also
-#' be directly used with an \code{lgb.Dataset} object.
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#'
-#' stopifnot(nrow(dtrain) == nrow(train$data))
-#' stopifnot(ncol(dtrain) == ncol(train$data))
-#' stopifnot(all(dim(dtrain) == dim(train$data)))
-#' }
-#' @rdname dim
-#' @export
-dim.lgb.Dataset <- function(x, ...) {
-
-  # Check if dataset is not a dataset
-  if (!lgb.is.Dataset(x = x)) {
-    stop("dim.lgb.Dataset: input data should be an lgb.Dataset object")
-  }
-
-  return(x$dim())
-
-}
-
-#' @title Handling of column names of \code{lgb.Dataset}
-#' @description Only column names are supported for \code{lgb.Dataset}, thus setting of
-#'              row names would have no effect and returned row names would be NULL.
-#' @param x object of class \code{lgb.Dataset}
-#' @param value a list of two elements: the first one is ignored
-#'              and the second one is column names
-#'
-#' @details
-#' Generic \code{dimnames} methods are used by \code{colnames}.
-#' Since row names are irrelevant, it is recommended to use \code{colnames} directly.
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' lgb.Dataset.construct(dtrain)
-#' dimnames(dtrain)
-#' colnames(dtrain)
-#' colnames(dtrain) <- make.names(seq_len(ncol(train$data)))
-#' print(dtrain, verbose = TRUE)
-#' }
-#' @rdname dimnames.lgb.Dataset
-#' @return A list with the dimension names of the dataset
-#' @export
-dimnames.lgb.Dataset <- function(x) {
-
-  # Check if dataset is not a dataset
-  if (!lgb.is.Dataset(x = x)) {
-    stop("dimnames.lgb.Dataset: input data should be an lgb.Dataset object")
-  }
-
-  # Return dimension names
-  return(list(NULL, x$get_colnames()))
-
-}
-
-#' @rdname dimnames.lgb.Dataset
-#' @export
-`dimnames<-.lgb.Dataset` <- function(x, value) {
-
-  # Check if invalid element list
-  if (!identical(class(value), "list") || length(value) != 2L) {
-    stop("invalid ", sQuote("value"), " given: must be a list of two elements")
-  }
-
-  # Check for unknown row names
-  if (!is.null(value[[1L]])) {
-    stop("lgb.Dataset does not have rownames")
-  }
-
-  if (is.null(value[[2L]])) {
-
-    x$set_colnames(colnames = NULL)
-    return(x)
-
-  }
-
-  # Check for unmatching column size
-  if (ncol(x) != length(value[[2L]])) {
-    stop(
-      "can't assign "
-      , sQuote(length(value[[2L]]))
-      , " colnames to an lgb.Dataset with "
-      , sQuote(ncol(x))
-      , " columns"
-    )
-  }
-
-  # Set column names properly, and return
-  x$set_colnames(colnames = value[[2L]])
-  return(x)
-
-}
-
-#' @title Slice a dataset
-#' @description Get a new \code{lgb.Dataset} containing the specified rows of
-#'              original \code{lgb.Dataset} object
-#' @param dataset Object of class \code{lgb.Dataset}
-#' @param idxset an integer vector of indices of rows needed
-#' @param ... other parameters (currently not used)
-#' @return constructed sub dataset
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#'
-#' dsub <- lightgbm::slice(dtrain, seq_len(42L))
-#' lgb.Dataset.construct(dsub)
-#' labels <- lightgbm::getinfo(dsub, "label")
-#' }
-#' @export
-slice <- function(dataset, ...) {
-  UseMethod("slice")
-}
-
-#' @rdname slice
-#' @export
-slice.lgb.Dataset <- function(dataset, idxset, ...) {
-
-  # Check if dataset is not a dataset
-  if (!lgb.is.Dataset(x = dataset)) {
-    stop("slice.lgb.Dataset: input dataset should be an lgb.Dataset object")
-  }
-
-  # Return sliced set
-  return(invisible(dataset$slice(idxset = idxset, ...)))
-
-}
-
-#' @name getinfo
-#' @title Get information of an \code{lgb.Dataset} object
-#' @description Get one attribute of a \code{lgb.Dataset}
-#' @param dataset Object of class \code{lgb.Dataset}
-#' @param name the name of the information field to get (see details)
-#' @param ... other parameters
-#' @return info data
-#'
-#' @details
-#' The \code{name} field can be one of the following:
-#'
-#' \itemize{
-#'     \item \code{label}: label lightgbm learn from ;
-#'     \item \code{weight}: to do a weight rescale ;
-#'     \item{\code{group}: used for learning-to-rank tasks. An integer vector describing how to
-#'         group rows together as ordered results from the same set of candidate results to be ranked.
-#'         For example, if you have a 100-document dataset with \code{group = c(10, 20, 40, 10, 10, 10)},
-#'         that means that you have 6 groups, where the first 10 records are in the first group,
-#'         records 11-30 are in the second group, etc.}
-#'     \item \code{init_score}: initial score is the base prediction lightgbm will boost from.
-#' }
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' lgb.Dataset.construct(dtrain)
-#'
-#' labels <- lightgbm::getinfo(dtrain, "label")
-#' lightgbm::setinfo(dtrain, "label", 1 - labels)
-#'
-#' labels2 <- lightgbm::getinfo(dtrain, "label")
-#' stopifnot(all(labels2 == 1 - labels))
-#' }
-#' @export
-getinfo <- function(dataset, ...) {
-  UseMethod("getinfo")
-}
-
-#' @rdname getinfo
-#' @export
-getinfo.lgb.Dataset <- function(dataset, name, ...) {
-
-  # Check if dataset is not a dataset
-  if (!lgb.is.Dataset(x = dataset)) {
-    stop("getinfo.lgb.Dataset: input dataset should be an lgb.Dataset object")
-  }
-
-  return(dataset$getinfo(name = name))
-
-}
-
-#' @name setinfo
-#' @title Set information of an \code{lgb.Dataset} object
-#' @description Set one attribute of a \code{lgb.Dataset}
-#' @param dataset Object of class \code{lgb.Dataset}
-#' @param name the name of the field to get
-#' @param info the specific field of information to set
-#' @param ... other parameters
-#' @return the dataset you passed in
-#'
-#' @details
-#' The \code{name} field can be one of the following:
-#'
-#' \itemize{
-#'     \item{\code{label}: vector of labels to use as the target variable}
-#'     \item{\code{weight}: to do a weight rescale}
-#'     \item{\code{init_score}: initial score is the base prediction lightgbm will boost from}
-#'     \item{\code{group}: used for learning-to-rank tasks. An integer vector describing how to
-#'         group rows together as ordered results from the same set of candidate results to be ranked.
-#'         For example, if you have a 100-document dataset with \code{group = c(10, 20, 40, 10, 10, 10)},
-#'         that means that you have 6 groups, where the first 10 records are in the first group,
-#'         records 11-30 are in the second group, etc.}
-#' }
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' lgb.Dataset.construct(dtrain)
-#'
-#' labels <- lightgbm::getinfo(dtrain, "label")
-#' lightgbm::setinfo(dtrain, "label", 1 - labels)
-#'
-#' labels2 <- lightgbm::getinfo(dtrain, "label")
-#' stopifnot(all.equal(labels2, 1 - labels))
-#' }
-#' @export
-setinfo <- function(dataset, ...) {
-  UseMethod("setinfo")
-}
-
-#' @rdname setinfo
-#' @export
-setinfo.lgb.Dataset <- function(dataset, name, info, ...) {
-
-  if (!lgb.is.Dataset(x = dataset)) {
-    stop("setinfo.lgb.Dataset: input dataset should be an lgb.Dataset object")
-  }
-
-  # Set information
-  return(invisible(dataset$setinfo(name = name, info = info)))
-}
-
-#' @name lgb.Dataset.set.categorical
-#' @title Set categorical feature of \code{lgb.Dataset}
-#' @description Set the categorical features of an \code{lgb.Dataset} object. Use this function
-#'              to tell LightGBM which features should be treated as categorical.
-#' @param dataset object of class \code{lgb.Dataset}
-#' @param categorical_feature categorical features. This can either be a character vector of feature
-#'                            names or an integer vector with the indices of the features (e.g.
-#'                            \code{c(1L, 10L)} to say "the first and tenth columns").
-#' @return the dataset you passed in
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data_file <- tempfile(fileext = ".data")
-#' lgb.Dataset.save(dtrain, data_file)
-#' dtrain <- lgb.Dataset(data_file)
-#' lgb.Dataset.set.categorical(dtrain, 1L:2L)
-#' }
-#' @rdname lgb.Dataset.set.categorical
-#' @export
-lgb.Dataset.set.categorical <- function(dataset, categorical_feature) {
-
-  if (!lgb.is.Dataset(x = dataset)) {
-    stop("lgb.Dataset.set.categorical: input dataset should be an lgb.Dataset object")
-  }
-
-  # Set categoricals
-  return(invisible(dataset$set_categorical_feature(categorical_feature = categorical_feature)))
-
-}
-
-#' @name lgb.Dataset.set.reference
-#' @title Set reference of \code{lgb.Dataset}
-#' @description If you want to use validation data, you should set reference to training data
-#' @param dataset object of class \code{lgb.Dataset}
-#' @param reference object of class \code{lgb.Dataset}
-#'
-#' @return the dataset you passed in
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package ="lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data(agaricus.test, package = "lightgbm")
-#' test <- agaricus.test
-#' dtest <- lgb.Dataset(test$data, test = train$label)
-#' lgb.Dataset.set.reference(dtest, dtrain)
-#' }
-#' @rdname lgb.Dataset.set.reference
-#' @export
-lgb.Dataset.set.reference <- function(dataset, reference) {
-
-  # Check if dataset is not a dataset
-  if (!lgb.is.Dataset(x = dataset)) {
-    stop("lgb.Dataset.set.reference: input dataset should be an lgb.Dataset object")
-  }
-
-  # Set reference
-  return(invisible(dataset$set_reference(reference = reference)))
-}
-
-#' @name lgb.Dataset.save
-#' @title Save \code{lgb.Dataset} to a binary file
-#' @description Please note that \code{init_score} is not saved in binary file.
-#'              If you need it, please set it again after loading Dataset.
-#' @param dataset object of class \code{lgb.Dataset}
-#' @param fname object filename of output file
-#'
-#' @return the dataset you passed in
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' lgb.Dataset.save(dtrain, tempfile(fileext = ".bin"))
-#' }
-#' @export
-lgb.Dataset.save <- function(dataset, fname) {
-
-  # Check if dataset is not a dataset
-  if (!lgb.is.Dataset(x = dataset)) {
-    stop("lgb.Dataset.set: input dataset should be an lgb.Dataset object")
-  }
-
-  # File-type is not matching
-  if (!is.character(fname)) {
-    stop("lgb.Dataset.set: fname should be a character or a file connection")
-  }
-
-  # Store binary
-  return(invisible(dataset$save_binary(fname = fname)))
-}
diff --git a/R-package/R/lgb.Predictor.R b/R-package/R/lgb.Predictor.R
deleted file mode 100644
index 73c4aa74a..000000000
--- a/R-package/R/lgb.Predictor.R
+++ /dev/null
@@ -1,241 +0,0 @@
-#' @importFrom methods is
-#' @importFrom R6 R6Class
-#' @importFrom utils read.delim
-Predictor <- R6::R6Class(
-
-  classname = "lgb.Predictor",
-  cloneable = FALSE,
-  public = list(
-
-    # Finalize will free up the handles
-    finalize = function() {
-
-      # Check the need for freeing handle
-      if (private$need_free_handle && !lgb.is.null.handle(x = private$handle)) {
-
-        # Freeing up handle
-        .Call(
-          LGBM_BoosterFree_R
-          , private$handle
-        )
-        private$handle <- NULL
-
-      }
-
-      return(invisible(NULL))
-
-    },
-
-    # Initialize will create a starter model
-    initialize = function(modelfile, ...) {
-      params <- list(...)
-      private$params <- lgb.params2str(params = params)
-      # Create new lgb handle
-      handle <- lgb.null.handle()
-
-      # Check if handle is a character
-      if (is.character(modelfile)) {
-
-        # Create handle on it
-        .Call(
-          LGBM_BoosterCreateFromModelfile_R
-          , modelfile
-          , handle
-        )
-        private$need_free_handle <- TRUE
-
-      } else if (methods::is(modelfile, "lgb.Booster.handle")) {
-
-        # Check if model file is a booster handle already
-        handle <- modelfile
-        private$need_free_handle <- FALSE
-
-      } else {
-
-        stop("lgb.Predictor: modelfile must be either a character filename or an lgb.Booster.handle")
-
-      }
-
-      # Override class and store it
-      class(handle) <- "lgb.Booster.handle"
-      private$handle <- handle
-
-      return(invisible(NULL))
-
-    },
-
-    # Get current iteration
-    current_iter = function() {
-
-      cur_iter <- 0L
-      .Call(
-        LGBM_BoosterGetCurrentIteration_R
-        , private$handle
-        , cur_iter
-      )
-      return(cur_iter)
-
-    },
-
-    # Predict from data
-    predict = function(data,
-                       start_iteration = NULL,
-                       num_iteration = NULL,
-                       rawscore = FALSE,
-                       predleaf = FALSE,
-                       predcontrib = FALSE,
-                       header = FALSE,
-                       reshape = FALSE) {
-
-      # Check if number of iterations is existing - if not, then set it to -1 (use all)
-      if (is.null(num_iteration)) {
-        num_iteration <- -1L
-      }
-      # Check if start iterations is existing - if not, then set it to 0 (start from the first iteration)
-      if (is.null(start_iteration)) {
-        start_iteration <- 0L
-      }
-
-      num_row <- 0L
-
-      # Check if data is a file name and not a matrix
-      if (identical(class(data), "character") && length(data) == 1L) {
-
-        # Data is a filename, create a temporary file with a "lightgbm_" pattern in it
-        tmp_filename <- tempfile(pattern = "lightgbm_")
-        on.exit(unlink(tmp_filename), add = TRUE)
-
-        # Predict from temporary file
-        .Call(
-          LGBM_BoosterPredictForFile_R
-          , private$handle
-          , data
-          , as.integer(header)
-          , as.integer(rawscore)
-          , as.integer(predleaf)
-          , as.integer(predcontrib)
-          , as.integer(start_iteration)
-          , as.integer(num_iteration)
-          , private$params
-          , tmp_filename
-        )
-
-        # Get predictions from file
-        preds <- utils::read.delim(tmp_filename, header = FALSE, sep = "\t")
-        num_row <- nrow(preds)
-        preds <- as.vector(t(preds))
-
-      } else {
-
-        # Not a file, we need to predict from R object
-        num_row <- nrow(data)
-
-        npred <- 0L
-
-        # Check number of predictions to do
-        .Call(
-          LGBM_BoosterCalcNumPredict_R
-          , private$handle
-          , as.integer(num_row)
-          , as.integer(rawscore)
-          , as.integer(predleaf)
-          , as.integer(predcontrib)
-          , as.integer(start_iteration)
-          , as.integer(num_iteration)
-          , npred
-        )
-
-        # Pre-allocate empty vector
-        preds <- numeric(npred)
-
-        # Check if data is a matrix
-        if (is.matrix(data)) {
-          # this if() prevents the memory and computational costs
-          # of converting something that is already "double" to "double"
-          if (storage.mode(data) != "double") {
-            storage.mode(data) <- "double"
-          }
-          .Call(
-            LGBM_BoosterPredictForMat_R
-            , private$handle
-            , data
-            , as.integer(nrow(data))
-            , as.integer(ncol(data))
-            , as.integer(rawscore)
-            , as.integer(predleaf)
-            , as.integer(predcontrib)
-            , as.integer(start_iteration)
-            , as.integer(num_iteration)
-            , private$params
-            , preds
-          )
-
-        } else if (methods::is(data, "dgCMatrix")) {
-          if (length(data@p) > 2147483647L) {
-            stop("Cannot support large CSC matrix")
-          }
-          # Check if data is a dgCMatrix (sparse matrix, column compressed format)
-          .Call(
-            LGBM_BoosterPredictForCSC_R
-            , private$handle
-            , data@p
-            , data@i
-            , data@x
-            , length(data@p)
-            , length(data@x)
-            , nrow(data)
-            , as.integer(rawscore)
-            , as.integer(predleaf)
-            , as.integer(predcontrib)
-            , as.integer(start_iteration)
-            , as.integer(num_iteration)
-            , private$params
-            , preds
-          )
-
-        } else {
-
-          stop("predict: cannot predict on data of class ", sQuote(class(data)))
-
-        }
-      }
-
-      # Check if number of rows is strange (not a multiple of the dataset rows)
-      if (length(preds) %% num_row != 0L) {
-        stop(
-          "predict: prediction length "
-          , sQuote(length(preds))
-          , " is not a multiple of nrows(data): "
-          , sQuote(num_row)
-        )
-      }
-
-      # Get number of cases per row
-      npred_per_case <- length(preds) / num_row
-
-
-      # Data reshaping
-
-      if (predleaf | predcontrib) {
-
-        # Predict leaves only, reshaping is mandatory
-        preds <- matrix(preds, ncol = npred_per_case, byrow = TRUE)
-
-      } else if (reshape && npred_per_case > 1L) {
-
-        # Predict with data reshaping
-        preds <- matrix(preds, ncol = npred_per_case, byrow = TRUE)
-
-      }
-
-      return(preds)
-
-    }
-
-  ),
-  private = list(
-    handle = NULL
-    , need_free_handle = FALSE
-    , params = ""
-  )
-)
diff --git a/R-package/R/lgb.convert_with_rules.R b/R-package/R/lgb.convert_with_rules.R
deleted file mode 100644
index 6e6f7fd03..000000000
--- a/R-package/R/lgb.convert_with_rules.R
+++ /dev/null
@@ -1,206 +0,0 @@
-# [description] get all column classes of a data.table or data.frame.
-#               This function collapses the result of class() into a single string
-.get_column_classes <- function(df) {
-    return(
-        vapply(
-            X = df
-            , FUN = function(x) {paste0(class(x), collapse = ",")}
-            , FUN.VALUE = character(1L)
-        )
-    )
-}
-
-# [description] check a data frame or data table for columns tthat are any
-#               type other than numeric and integer. This is used by lgb.convert()
-#               and lgb.convert_with_rules() too warn if more action is needed by users
-#               before a dataset can be converted to a lgb.Dataset.
-.warn_for_unconverted_columns <- function(df, function_name) {
-    column_classes <- .get_column_classes(df = df)
-    unconverted_columns <- column_classes[!(column_classes %in% c("numeric", "integer"))]
-    if (length(unconverted_columns) > 0L) {
-        col_detail_string <- paste0(
-            paste0(
-                names(unconverted_columns)
-                , " ("
-                , unconverted_columns
-                , ")"
-            )
-            , collapse = ", "
-        )
-        msg <- paste0(
-            function_name
-            , ": "
-            , length(unconverted_columns)
-            , " columns are not numeric or integer. These need to be dropped or converted to "
-            , "be used in an lgb.Dataset object. "
-            , col_detail_string
-        )
-        warning(msg)
-    }
-    return(invisible(NULL))
-}
-
-.LGB_CONVERT_DEFAULT_FOR_LOGICAL_NA <- function() {return(-1L)}
-.LGB_CONVERT_DEFAULT_FOR_NON_LOGICAL_NA <- function() {return(0L)}
-
-
-#' @name lgb.convert_with_rules
-#' @title Data preparator for LightGBM datasets with rules (integer)
-#' @description Attempts to prepare a clean dataset to prepare to put in a \code{lgb.Dataset}.
-#'              Factor, character, and logical columns are converted to integer. Missing values
-#'              in factors and characters will be filled with 0L. Missing values in logicals
-#'              will be filled with -1L.
-#'
-#'              This function returns and optionally takes in "rules" the describe exactly
-#'              how to convert values in columns.
-#'
-#'              Columns that contain only NA values will be converted by this function but will
-#'              not show up in the returned \code{rules}.
-#'
-#'              NOTE: In previous releases of LightGBM, this function was called \code{lgb.prepare_rules2}.
-#' @param data A data.frame or data.table to prepare.
-#' @param rules A set of rules from the data preparator, if already used. This should be an R list,
-#'              where names are column names in \code{data} and values are named character
-#'              vectors whose names are column values and whose values are new values to
-#'              replace them with.
-#' @return A list with the cleaned dataset (\code{data}) and the rules (\code{rules}).
-#'         Note that the data must be converted to a matrix format (\code{as.matrix}) for input in
-#'         \code{lgb.Dataset}.
-#'
-#' @examples
-#' \donttest{
-#' data(iris)
-#'
-#' str(iris)
-#'
-#' new_iris <- lgb.convert_with_rules(data = iris)
-#' str(new_iris$data)
-#'
-#' data(iris) # Erase iris dataset
-#' iris$Species[1L] <- "NEW FACTOR" # Introduce junk factor (NA)
-#'
-#' # Use conversion using known rules
-#' # Unknown factors become 0, excellent for sparse datasets
-#' newer_iris <- lgb.convert_with_rules(data = iris, rules = new_iris$rules)
-#'
-#' # Unknown factor is now zero, perfect for sparse datasets
-#' newer_iris$data[1L, ] # Species became 0 as it is an unknown factor
-#'
-#' newer_iris$data[1L, 5L] <- 1.0 # Put back real initial value
-#'
-#' # Is the newly created dataset equal? YES!
-#' all.equal(new_iris$data, newer_iris$data)
-#'
-#' # Can we test our own rules?
-#' data(iris) # Erase iris dataset
-#'
-#' # We remapped values differently
-#' personal_rules <- list(
-#'   Species = c(
-#'     "setosa" = 3L
-#'     , "versicolor" = 2L
-#'     , "virginica" = 1L
-#'   )
-#' )
-#' newest_iris <- lgb.convert_with_rules(data = iris, rules = personal_rules)
-#' str(newest_iris$data) # SUCCESS!
-#' }
-#' @importFrom data.table set
-#' @export
-lgb.convert_with_rules <- function(data, rules = NULL) {
-
-    column_classes <- .get_column_classes(df = data)
-
-    is_char <- which(column_classes == "character")
-    is_factor <- which(column_classes == "factor")
-    is_logical <- which(column_classes == "logical")
-
-    is_data_table <- data.table::is.data.table(x = data)
-    is_data_frame <- is.data.frame(data)
-
-    if (!(is_data_table || is_data_frame)) {
-        stop(
-            "lgb.convert_with_rules: you provided "
-            , paste(class(data), collapse = " & ")
-            , " but data should have class data.frame or data.table"
-        )
-    }
-
-    # if user didn't provide rules, create them
-    if (is.null(rules)) {
-        rules <- list()
-        columns_to_fix <- which(column_classes %in% c("character", "factor", "logical"))
-
-        for (i in columns_to_fix) {
-
-          col_values <- data[[i]]
-
-          # Get unique values
-          if (is.factor(col_values)) {
-              unique_vals <- levels(col_values)
-              unique_vals <- unique_vals[!is.na(unique_vals)]
-              mini_numeric <- seq_along(unique_vals) # respect ordinal
-          } else if (is.character(col_values)) {
-              unique_vals <- as.factor(unique(col_values))
-              unique_vals <- unique_vals[!is.na(unique_vals)]
-              mini_numeric <- as.integer(unique_vals)  # no respect for ordinal
-          } else if (is.logical(col_values)) {
-              unique_vals <- c(FALSE, TRUE)
-              mini_numeric <- c(0L, 1L)
-          }
-
-          # don't add rules for all-NA columns
-          if (length(unique_vals) > 0L) {
-              col_name <- names(data)[i]
-              rules[[col_name]] <- mini_numeric
-              names(rules[[col_name]]) <- unique_vals
-          }
-        }
-    }
-
-    for (col_name in names(rules)) {
-        if (column_classes[[col_name]] == "logical") {
-            default_value_for_na <- .LGB_CONVERT_DEFAULT_FOR_LOGICAL_NA()
-        } else {
-            default_value_for_na <- .LGB_CONVERT_DEFAULT_FOR_NON_LOGICAL_NA()
-        }
-        if (is_data_table) {
-            data.table::set(
-                x = data
-                , j = col_name
-                , value = unname(rules[[col_name]][data[[col_name]]])
-            )
-            data[is.na(get(col_name)), (col_name) := default_value_for_na]
-        } else {
-            data[[col_name]] <- unname(rules[[col_name]][data[[col_name]]])
-            data[is.na(data[col_name]), col_name] <- default_value_for_na
-        }
-    }
-
-    # if any all-NA columns exist, they won't be in rules. Convert them
-    all_na_cols <- which(
-        sapply(
-            X = data
-            , FUN = function(x) {
-                (is.factor(x) || is.character(x) || is.logical(x)) && all(is.na(unique(x)))
-            }
-        )
-    )
-    for (col_name in all_na_cols) {
-        if (column_classes[[col_name]] == "logical") {
-            default_value_for_na <- .LGB_CONVERT_DEFAULT_FOR_LOGICAL_NA()
-        } else {
-            default_value_for_na <- .LGB_CONVERT_DEFAULT_FOR_NON_LOGICAL_NA()
-        }
-        if (is_data_table) {
-            data[, (col_name) := rep(default_value_for_na, .N)]
-        } else {
-            data[[col_name]] <- default_value_for_na
-        }
-    }
-
-    .warn_for_unconverted_columns(df = data, function_name = "lgb.convert_with_rules")
-
-    return(list(data = data, rules = rules))
-
-}
diff --git a/R-package/R/lgb.cv.R b/R-package/R/lgb.cv.R
deleted file mode 100644
index 74a4e4d64..000000000
--- a/R-package/R/lgb.cv.R
+++ /dev/null
@@ -1,635 +0,0 @@
-#' @importFrom R6 R6Class
-CVBooster <- R6::R6Class(
-  classname = "lgb.CVBooster",
-  cloneable = FALSE,
-  public = list(
-    best_iter = -1L,
-    best_score = NA,
-    record_evals = list(),
-    boosters = list(),
-    initialize = function(x) {
-      self$boosters <- x
-      return(invisible(NULL))
-    },
-    reset_parameter = function(new_params) {
-      for (x in boosters) { x$reset_parameter(new_params) }
-      return(invisible(self))
-    }
-  )
-)
-
-#' @name lgb.cv
-#' @title Main CV logic for LightGBM
-#' @description Cross validation logic used by LightGBM
-#' @inheritParams lgb_shared_params
-#' @param nfold the original dataset is randomly partitioned into \code{nfold} equal size subsamples.
-#' @param label Vector of labels, used if \code{data} is not an \code{\link{lgb.Dataset}}
-#' @param weight vector of response values. If not NULL, will set to dataset
-#' @param record Boolean, TRUE will record iteration message to \code{booster$record_evals}
-#' @param showsd \code{boolean}, whether to show standard deviation of cross validation
-#' @param stratified a \code{boolean} indicating whether sampling of folds should be stratified
-#'                   by the values of outcome labels.
-#' @param folds \code{list} provides a possibility to use a list of pre-defined CV folds
-#'              (each element must be a vector of test fold's indices). When folds are supplied,
-#'              the \code{nfold} and \code{stratified} parameters are ignored.
-#' @param colnames feature names, if not null, will use this to overwrite the names in dataset
-#' @param categorical_feature categorical features. This can either be a character vector of feature
-#'                            names or an integer vector with the indices of the features (e.g.
-#'                            \code{c(1L, 10L)} to say "the first and tenth columns").
-#' @param callbacks List of callback functions that are applied at each iteration.
-#' @param reset_data Boolean, setting it to TRUE (not the default value) will transform the booster model
-#'                   into a predictor model which frees up memory and the original datasets
-#' @param ... other parameters, see Parameters.rst for more information. A few key parameters:
-#'            \itemize{
-#'                \item{\code{boosting}: Boosting type. \code{"gbdt"}, \code{"rf"}, \code{"dart"} or \code{"goss"}.}
-#'                \item{\code{num_leaves}: Maximum number of leaves in one tree.}
-#'                \item{\code{max_depth}: Limit the max depth for tree model. This is used to deal with
-#'                                 overfit when #data is small. Tree still grow by leaf-wise.}
-#'                \item{\code{num_threads}: Number of threads for LightGBM. For the best speed, set this to
-#'                             the number of real CPU cores(\code{parallel::detectCores(logical = FALSE)}),
-#'                             not the number of threads (most CPU using hyper-threading to generate 2 threads
-#'                             per CPU core).}
-#'            }
-#' @inheritSection lgb_shared_params Early Stopping
-#' @return a trained model \code{lgb.CVBooster}.
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' params <- list(objective = "regression", metric = "l2")
-#' model <- lgb.cv(
-#'   params = params
-#'   , data = dtrain
-#'   , nrounds = 5L
-#'   , nfold = 3L
-#'   , min_data = 1L
-#'   , learning_rate = 1.0
-#' )
-#' }
-#' @importFrom data.table data.table setorderv
-#' @export
-lgb.cv <- function(params = list()
-                   , data
-                   , nrounds = 100L
-                   , nfold = 3L
-                   , label = NULL
-                   , weight = NULL
-                   , obj = NULL
-                   , eval = NULL
-                   , verbose = 1L
-                   , record = TRUE
-                   , eval_freq = 1L
-                   , showsd = TRUE
-                   , stratified = TRUE
-                   , folds = NULL
-                   , init_model = NULL
-                   , colnames = NULL
-                   , categorical_feature = NULL
-                   , early_stopping_rounds = NULL
-                   , callbacks = list()
-                   , reset_data = FALSE
-                   , ...
-                   ) {
-
-  if (nrounds <= 0L) {
-    stop("nrounds should be greater than zero")
-  }
-
-  # If 'data' is not an lgb.Dataset, try to construct one using 'label'
-  if (!lgb.is.Dataset(x = data)) {
-    if (is.null(label)) {
-      stop("'label' must be provided for lgb.cv if 'data' is not an 'lgb.Dataset'")
-    }
-    data <- lgb.Dataset(data = data, label = label)
-  }
-
-  # Setup temporary variables
-  params <- append(params, list(...))
-  params$verbose <- verbose
-  params <- lgb.check.obj(params = params, obj = obj)
-  params <- lgb.check.eval(params = params, eval = eval)
-  fobj <- NULL
-  eval_functions <- list(NULL)
-
-  # set some parameters, resolving the way they were passed in with other parameters
-  # in `params`.
-  # this ensures that the model stored with Booster$save() correctly represents
-  # what was passed in
-  params <- lgb.check.wrapper_param(
-    main_param_name = "num_iterations"
-    , params = params
-    , alternative_kwarg_value = nrounds
-  )
-  params <- lgb.check.wrapper_param(
-    main_param_name = "early_stopping_round"
-    , params = params
-    , alternative_kwarg_value = early_stopping_rounds
-  )
-  early_stopping_rounds <- params[["early_stopping_round"]]
-
-  # Check for objective (function or not)
-  if (is.function(params$objective)) {
-    fobj <- params$objective
-    params$objective <- "NONE"
-  }
-
-  # If eval is a single function, store it as a 1-element list
-  # (for backwards compatibility). If it is a list of functions, store
-  # all of them. This makes it possible to pass any mix of strings like "auc"
-  # and custom functions to eval
-  if (is.function(eval)) {
-    eval_functions <- list(eval)
-  }
-  if (methods::is(eval, "list")) {
-    eval_functions <- Filter(
-      f = is.function
-      , x = eval
-    )
-  }
-
-  # Init predictor to empty
-  predictor <- NULL
-
-  # Check for boosting from a trained model
-  if (is.character(init_model)) {
-    predictor <- Predictor$new(modelfile = init_model)
-  } else if (lgb.is.Booster(x = init_model)) {
-    predictor <- init_model$to_predictor()
-  }
-
-  # Set the iteration to start from / end to (and check for boosting from a trained model, again)
-  begin_iteration <- 1L
-  if (!is.null(predictor)) {
-    begin_iteration <- predictor$current_iter() + 1L
-  }
-  end_iteration <- begin_iteration + params[["num_iterations"]] - 1L
-
-  # pop interaction_constraints off of params. It needs some preprocessing on the
-  # R side before being passed into the Dataset object
-  interaction_constraints <- params[["interaction_constraints"]]
-  params["interaction_constraints"] <- NULL
-
-  # Construct datasets, if needed
-  data$update_params(params = params)
-  data$construct()
-
-  # Check interaction constraints
-  cnames <- NULL
-  if (!is.null(colnames)) {
-    cnames <- colnames
-  } else if (!is.null(data$get_colnames())) {
-    cnames <- data$get_colnames()
-  }
-  params[["interaction_constraints"]] <- lgb.check_interaction_constraints(
-    interaction_constraints = interaction_constraints
-    , column_names = cnames
-  )
-
-  # Check for weights
-  if (!is.null(weight)) {
-    data$setinfo(name = "weight", info = weight)
-  }
-
-  # Update parameters with parsed parameters
-  data$update_params(params = params)
-
-  # Create the predictor set
-  data$.__enclos_env__$private$set_predictor(predictor = predictor)
-
-  # Write column names
-  if (!is.null(colnames)) {
-    data$set_colnames(colnames = colnames)
-  }
-
-  # Write categorical features
-  if (!is.null(categorical_feature)) {
-    data$set_categorical_feature(categorical_feature = categorical_feature)
-  }
-
-  # Check for folds
-  if (!is.null(folds)) {
-
-    # Check for list of folds or for single value
-    if (!identical(class(folds), "list") || length(folds) < 2L) {
-      stop(sQuote("folds"), " must be a list with 2 or more elements that are vectors of indices for each CV-fold")
-    }
-
-    # Set number of folds
-    nfold <- length(folds)
-
-  } else {
-
-    # Check fold value
-    if (nfold <= 1L) {
-      stop(sQuote("nfold"), " must be > 1")
-    }
-
-    # Create folds
-    folds <- generate.cv.folds(
-      nfold = nfold
-      , nrows = nrow(data)
-      , stratified = stratified
-      , label = getinfo(dataset = data, name = "label")
-      , group = getinfo(dataset = data, name = "group")
-      , params = params
-    )
-
-  }
-
-  # Add printing log callback
-  if (verbose > 0L && eval_freq > 0L) {
-    callbacks <- add.cb(cb_list = callbacks, cb = cb.print.evaluation(period = eval_freq))
-  }
-
-  # Add evaluation log callback
-  if (record) {
-    callbacks <- add.cb(cb_list = callbacks, cb = cb.record.evaluation())
-  }
-
-  # Did user pass parameters that indicate they want to use early stopping?
-  using_early_stopping <- !is.null(early_stopping_rounds) && early_stopping_rounds > 0L
-
-  boosting_param_names <- .PARAMETER_ALIASES()[["boosting"]]
-  using_dart <- any(
-    sapply(
-      X = boosting_param_names
-      , FUN = function(param) {
-        identical(params[[param]], "dart")
-      }
-    )
-  )
-
-  # Cannot use early stopping with 'dart' boosting
-  if (using_dart) {
-    warning("Early stopping is not available in 'dart' mode.")
-    using_early_stopping <- FALSE
-
-    # Remove the cb.early.stop() function if it was passed in to callbacks
-    callbacks <- Filter(
-      f = function(cb_func) {
-        !identical(attr(cb_func, "name"), "cb.early.stop")
-      }
-      , x = callbacks
-    )
-  }
-
-  # If user supplied early_stopping_rounds, add the early stopping callback
-  if (using_early_stopping) {
-    callbacks <- add.cb(
-      cb_list = callbacks
-      , cb = cb.early.stop(
-        stopping_rounds = early_stopping_rounds
-        , first_metric_only = isTRUE(params[["first_metric_only"]])
-        , verbose = verbose
-      )
-    )
-  }
-
-  cb <- categorize.callbacks(cb_list = callbacks)
-
-  # Construct booster for each fold. The data.table() code below is used to
-  # guarantee that indices are sorted while keeping init_score and weight together
-  # with the correct indices. Note that it takes advantage of the fact that
-  # someDT$some_column returns NULL is 'some_column' does not exist in the data.table
-  bst_folds <- lapply(
-    X = seq_along(folds)
-    , FUN = function(k) {
-
-      # For learning-to-rank, each fold is a named list with two elements:
-      #   * `fold` = an integer vector of row indices
-      #   * `group` = an integer vector describing which groups are in the fold
-      # For classification or regression tasks, it will just be an integer
-      # vector of row indices
-      folds_have_group <- "group" %in% names(folds[[k]])
-      if (folds_have_group) {
-        test_indices <- folds[[k]]$fold
-        test_group_indices <- folds[[k]]$group
-        test_groups <- getinfo(dataset = data, name = "group")[test_group_indices]
-        train_groups <- getinfo(dataset = data, name = "group")[-test_group_indices]
-      } else {
-        test_indices <- folds[[k]]
-      }
-      train_indices <- seq_len(nrow(data))[-test_indices]
-
-      # set up test set
-      indexDT <- data.table::data.table(
-        indices = test_indices
-        , weight = getinfo(dataset = data, name = "weight")[test_indices]
-        , init_score = getinfo(dataset = data, name = "init_score")[test_indices]
-      )
-      data.table::setorderv(x = indexDT, cols = "indices", order = 1L)
-      dtest <- slice(data, indexDT$indices)
-      setinfo(dataset = dtest, name = "weight", info = indexDT$weight)
-      setinfo(dataset = dtest, name = "init_score", info = indexDT$init_score)
-
-      # set up training set
-      indexDT <- data.table::data.table(
-        indices = train_indices
-        , weight = getinfo(dataset = data, name = "weight")[train_indices]
-        , init_score = getinfo(dataset = data, name = "init_score")[train_indices]
-      )
-      data.table::setorderv(x = indexDT, cols = "indices", order = 1L)
-      dtrain <- slice(data, indexDT$indices)
-      setinfo(dataset = dtrain, name = "weight", info = indexDT$weight)
-      setinfo(dataset = dtrain, name = "init_score", info = indexDT$init_score)
-
-      if (folds_have_group) {
-        setinfo(dataset = dtest, name = "group", info = test_groups)
-        setinfo(dataset = dtrain, name = "group", info = train_groups)
-      }
-
-      booster <- Booster$new(params = params, train_set = dtrain)
-      booster$add_valid(data = dtest, name = "valid")
-      return(
-        list(booster = booster)
-      )
-    }
-  )
-
-  # Create new booster
-  cv_booster <- CVBooster$new(x = bst_folds)
-
-  # Callback env
-  env <- CB_ENV$new()
-  env$model <- cv_booster
-  env$begin_iteration <- begin_iteration
-  env$end_iteration <- end_iteration
-
-  # Start training model using number of iterations to start and end with
-  for (i in seq.int(from = begin_iteration, to = end_iteration)) {
-
-    # Overwrite iteration in environment
-    env$iteration <- i
-    env$eval_list <- list()
-
-    for (f in cb$pre_iter) {
-      f(env)
-    }
-
-    # Update one boosting iteration
-    msg <- lapply(cv_booster$boosters, function(fd) {
-      fd$booster$update(fobj = fobj)
-      out <- list()
-      for (eval_function in eval_functions) {
-        out <- append(out, fd$booster$eval_valid(feval = eval_function))
-      }
-      return(out)
-    })
-
-    # Prepare collection of evaluation results
-    merged_msg <- lgb.merge.cv.result(msg = msg)
-
-    # Write evaluation result in environment
-    env$eval_list <- merged_msg$eval_list
-
-    # Check for standard deviation requirement
-    if (showsd) {
-      env$eval_err_list <- merged_msg$eval_err_list
-    }
-
-    # Loop through env
-    for (f in cb$post_iter) {
-      f(env)
-    }
-
-    # Check for early stopping and break if needed
-    if (env$met_early_stop) break
-
-  }
-
-  # When early stopping is not activated, we compute the best iteration / score ourselves
-  # based on the first first metric
-  if (record && is.na(env$best_score)) {
-    # when using a custom eval function, the metric name is returned from the
-    # function, so figure it out from record_evals
-    if (!is.null(eval_functions[1L])) {
-      first_metric <- names(cv_booster$record_evals[["valid"]])[1L]
-    } else {
-      first_metric <- cv_booster$.__enclos_env__$private$eval_names[1L]
-    }
-    .find_best <- which.min
-    if (isTRUE(env$eval_list[[1L]]$higher_better[1L])) {
-      .find_best <- which.max
-    }
-    cv_booster$best_iter <- unname(
-      .find_best(
-        unlist(
-          cv_booster$record_evals[["valid"]][[first_metric]][[.EVAL_KEY()]]
-        )
-      )
-    )
-    cv_booster$best_score <- cv_booster$record_evals[["valid"]][[first_metric]][[.EVAL_KEY()]][[cv_booster$best_iter]]
-  }
-
-  if (reset_data) {
-    lapply(cv_booster$boosters, function(fd) {
-      # Store temporarily model data elsewhere
-      booster_old <- list(
-        best_iter = fd$booster$best_iter
-        , best_score = fd$booster$best_score
-        , record_evals = fd$booster$record_evals
-      )
-      # Reload model
-      fd$booster <- lgb.load(model_str = fd$booster$save_model_to_string())
-      fd$booster$best_iter <- booster_old$best_iter
-      fd$booster$best_score <- booster_old$best_score
-      fd$booster$record_evals <- booster_old$record_evals
-    })
-  }
-
-  return(cv_booster)
-
-}
-
-# Generates random (stratified if needed) CV folds
-generate.cv.folds <- function(nfold, nrows, stratified, label, group, params) {
-
-  # Check for group existence
-  if (is.null(group)) {
-
-    # Shuffle
-    rnd_idx <- sample.int(nrows)
-
-    # Request stratified folds
-    if (isTRUE(stratified) && params$objective %in% c("binary", "multiclass") && length(label) == length(rnd_idx)) {
-
-      y <- label[rnd_idx]
-      y <- as.factor(y)
-      folds <- lgb.stratified.folds(y = y, k = nfold)
-
-    } else {
-
-      # Make simple non-stratified folds
-      folds <- list()
-
-      # Loop through each fold
-      for (i in seq_len(nfold)) {
-        kstep <- length(rnd_idx) %/% (nfold - i + 1L)
-        folds[[i]] <- rnd_idx[seq_len(kstep)]
-        rnd_idx <- rnd_idx[-seq_len(kstep)]
-      }
-
-    }
-
-  } else {
-
-    # When doing group, stratified is not possible (only random selection)
-    if (nfold > length(group)) {
-      stop("\nYou requested too many folds for the number of available groups.\n")
-    }
-
-    # Degroup the groups
-    ungrouped <- inverse.rle(list(lengths = group, values = seq_along(group)))
-
-    # Can't stratify, shuffle
-    rnd_idx <- sample.int(length(group))
-
-    # Make simple non-stratified folds
-    folds <- list()
-
-    # Loop through each fold
-    for (i in seq_len(nfold)) {
-      kstep <- length(rnd_idx) %/% (nfold - i + 1L)
-      folds[[i]] <- list(
-        fold = which(ungrouped %in% rnd_idx[seq_len(kstep)])
-        , group = rnd_idx[seq_len(kstep)]
-      )
-      rnd_idx <- rnd_idx[-seq_len(kstep)]
-    }
-
-  }
-
-  return(folds)
-
-}
-
-# Creates CV folds stratified by the values of y.
-# It was borrowed from caret::createFolds and simplified
-# by always returning an unnamed list of fold indices.
-#' @importFrom stats quantile
-lgb.stratified.folds <- function(y, k = 10L) {
-
-  ## Group the numeric data based on their magnitudes
-  ## and sample within those groups.
-  ## When the number of samples is low, we may have
-  ## issues further slicing the numeric data into
-  ## groups. The number of groups will depend on the
-  ## ratio of the number of folds to the sample size.
-  ## At most, we will use quantiles. If the sample
-  ## is too small, we just do regular unstratified CV
-  if (is.numeric(y)) {
-
-    cuts <- length(y) %/% k
-    if (cuts < 2L) {
-      cuts <- 2L
-    }
-    if (cuts > 5L) {
-      cuts <- 5L
-    }
-    y <- cut(
-      y
-      , unique(stats::quantile(y, probs = seq.int(0.0, 1.0, length.out = cuts)))
-      , include.lowest = TRUE
-    )
-
-  }
-
-  if (k < length(y)) {
-
-    ## Reset levels so that the possible levels and
-    ## the levels in the vector are the same
-    y <- as.factor(as.character(y))
-    numInClass <- table(y)
-    foldVector <- vector(mode = "integer", length(y))
-
-    ## For each class, balance the fold allocation as far
-    ## as possible, then resample the remainder.
-    ## The final assignment of folds is also randomized.
-
-    for (i in seq_along(numInClass)) {
-
-      ## Create a vector of integers from 1:k as many times as possible without
-      ## going over the number of samples in the class. Note that if the number
-      ## of samples in a class is less than k, nothing is producd here.
-      seqVector <- rep(seq_len(k), numInClass[i] %/% k)
-
-      ## Add enough random integers to get  length(seqVector) == numInClass[i]
-      if (numInClass[i] %% k > 0L) {
-        seqVector <- c(seqVector, sample.int(k, numInClass[i] %% k))
-      }
-
-      ## Shuffle the integers for fold assignment and assign to this classes's data
-      foldVector[y == dimnames(numInClass)$y[i]] <- sample(seqVector)
-
-    }
-
-  } else {
-
-    foldVector <- seq(along = y)
-
-  }
-
-  out <- split(seq(along = y), foldVector)
-  names(out) <- NULL
-  return(out)
-}
-
-lgb.merge.cv.result <- function(msg, showsd = TRUE) {
-
-  # Get CV message length
-  if (length(msg) == 0L) {
-    stop("lgb.cv: size of cv result error")
-  }
-
-  # Get evaluation message length
-  eval_len <- length(msg[[1L]])
-
-  # Is evaluation message empty?
-  if (eval_len == 0L) {
-    stop("lgb.cv: should provide at least one metric for CV")
-  }
-
-  # Get evaluation results using a list apply
-  eval_result <- lapply(seq_len(eval_len), function(j) {
-    as.numeric(lapply(seq_along(msg), function(i) {
-      msg[[i]][[j]]$value }))
-  })
-
-  # Get evaluation. Just taking the first element here to
-  # get structure (name, higher_better, data_name)
-  ret_eval <- msg[[1L]]
-
-  # Go through evaluation length items
-  for (j in seq_len(eval_len)) {
-    ret_eval[[j]]$value <- mean(eval_result[[j]])
-  }
-
-  ret_eval_err <- NULL
-
-  # Check for standard deviation
-  if (showsd) {
-
-    # Parse standard deviation
-    for (j in seq_len(eval_len)) {
-      ret_eval_err <- c(
-        ret_eval_err
-        , sqrt(mean(eval_result[[j]] ^ 2L) - mean(eval_result[[j]]) ^ 2L)
-      )
-    }
-
-    # Convert to list
-    ret_eval_err <- as.list(ret_eval_err)
-
-  }
-
-  # Return errors
-  return(
-    list(
-      eval_list = ret_eval
-      , eval_err_list = ret_eval_err
-    )
-  )
-
-}
diff --git a/R-package/R/lgb.importance.R b/R-package/R/lgb.importance.R
deleted file mode 100644
index d91a00c85..000000000
--- a/R-package/R/lgb.importance.R
+++ /dev/null
@@ -1,81 +0,0 @@
-#' @name lgb.importance
-#' @title Compute feature importance in a model
-#' @description Creates a \code{data.table} of feature importances in a model.
-#' @param model object of class \code{lgb.Booster}.
-#' @param percentage whether to show importance in relative percentage.
-#'
-#' @return For a tree model, a \code{data.table} with the following columns:
-#' \itemize{
-#'   \item{\code{Feature}: Feature names in the model.}
-#'   \item{\code{Gain}: The total gain of this feature's splits.}
-#'   \item{\code{Cover}: The number of observation related to this feature.}
-#'   \item{\code{Frequency}: The number of times a feature splited in trees.}
-#' }
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#'
-#' params <- list(
-#'   objective = "binary"
-#'   , learning_rate = 0.1
-#'   , max_depth = -1L
-#'   , min_data_in_leaf = 1L
-#'   , min_sum_hessian_in_leaf = 1.0
-#' )
-#' model <- lgb.train(
-#'     params = params
-#'     , data = dtrain
-#'     , nrounds = 5L
-#' )
-#'
-#' tree_imp1 <- lgb.importance(model, percentage = TRUE)
-#' tree_imp2 <- lgb.importance(model, percentage = FALSE)
-#' }
-#' @importFrom data.table := setnames setorderv
-#' @export
-lgb.importance <- function(model, percentage = TRUE) {
-
-  # Check if model is a lightgbm model
-  if (!lgb.is.Booster(x = model)) {
-    stop("'model' has to be an object of class lgb.Booster")
-  }
-
-  # Setup importance
-  tree_dt <- lgb.model.dt.tree(model = model)
-
-  # Extract elements
-  tree_imp_dt <- tree_dt[
-    !is.na(split_index)
-    , .(Gain = sum(split_gain), Cover = sum(internal_count), Frequency = .N)
-    , by = "split_feature"
-  ]
-
-  data.table::setnames(
-    x = tree_imp_dt
-    , old = "split_feature"
-    , new = "Feature"
-  )
-
-  # Sort features by Gain
-  data.table::setorderv(
-    x = tree_imp_dt
-    , cols = "Gain"
-    , order = -1L
-  )
-
-  # Check if relative values are requested
-  if (percentage) {
-    tree_imp_dt[, `:=`(
-      Gain = Gain / sum(Gain)
-      , Cover = Cover / sum(Cover)
-      , Frequency = Frequency / sum(Frequency)
-    )]
-  }
-
-  # adding an empty [] to ensure the table is printed the first time print.data.table() is called
-  return(tree_imp_dt[])
-
-}
diff --git a/R-package/R/lgb.interprete.R b/R-package/R/lgb.interprete.R
deleted file mode 100644
index 3a6cb7400..000000000
--- a/R-package/R/lgb.interprete.R
+++ /dev/null
@@ -1,243 +0,0 @@
-#' @name lgb.interprete
-#' @title Compute feature contribution of prediction
-#' @description Computes feature contribution components of rawscore prediction.
-#' @param model object of class \code{lgb.Booster}.
-#' @param data a matrix object or a dgCMatrix object.
-#' @param idxset an integer vector of indices of rows needed.
-#' @param num_iteration number of iteration want to predict with, NULL or <= 0 means use best iteration.
-#'
-#' @return For regression, binary classification and lambdarank model, a \code{list} of \code{data.table}
-#'         with the following columns:
-#'         \itemize{
-#'             \item{\code{Feature}: Feature names in the model.}
-#'             \item{\code{Contribution}: The total contribution of this feature's splits.}
-#'         }
-#'         For multiclass classification, a \code{list} of \code{data.table} with the Feature column and
-#'         Contribution columns to each class.
-#'
-#' @examples
-#' \donttest{
-#' Logit <- function(x) log(x / (1.0 - x))
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' setinfo(dtrain, "init_score", rep(Logit(mean(train$label)), length(train$label)))
-#' data(agaricus.test, package = "lightgbm")
-#' test <- agaricus.test
-#'
-#' params <- list(
-#'     objective = "binary"
-#'     , learning_rate = 0.1
-#'     , max_depth = -1L
-#'     , min_data_in_leaf = 1L
-#'     , min_sum_hessian_in_leaf = 1.0
-#' )
-#' model <- lgb.train(
-#'     params = params
-#'     , data = dtrain
-#'     , nrounds = 3L
-#' )
-#'
-#' tree_interpretation <- lgb.interprete(model, test$data, 1L:5L)
-#' }
-#' @importFrom data.table as.data.table
-#' @export
-lgb.interprete <- function(model,
-                           data,
-                           idxset,
-                           num_iteration = NULL) {
-
-  # Get tree model
-  tree_dt <- lgb.model.dt.tree(model = model, num_iteration = num_iteration)
-
-  # Check number of classes
-  num_class <- model$.__enclos_env__$private$num_class
-
-  # Get vector list
-  tree_interpretation_dt_list <- vector(mode = "list", length = length(idxset))
-
-  # Get parsed predictions of data
-  pred_mat <- t(
-    model$predict(
-      data = data[idxset, , drop = FALSE]
-      , num_iteration = num_iteration
-      , predleaf = TRUE
-    )
-  )
-  leaf_index_dt <- data.table::as.data.table(x = pred_mat)
-  leaf_index_mat_list <- lapply(
-    X = leaf_index_dt
-    , FUN = function(x) matrix(x, ncol = num_class, byrow = TRUE)
-  )
-
-  # Get list of trees
-  tree_index_mat_list <- lapply(
-    X = leaf_index_mat_list
-    , FUN = function(x) {
-      matrix(seq_len(length(x)) - 1L, ncol = num_class, byrow = TRUE)
-    }
-  )
-
-  # Sequence over idxset
-  for (i in seq_along(idxset)) {
-    tree_interpretation_dt_list[[i]] <- single.row.interprete(
-      tree_dt = tree_dt
-      , num_class = num_class
-      , tree_index_mat = tree_index_mat_list[[i]]
-      , leaf_index_mat = leaf_index_mat_list[[i]]
-    )
-  }
-
-  return(tree_interpretation_dt_list)
-
-}
-
-#' @importFrom data.table data.table
-single.tree.interprete <- function(tree_dt,
-                                   tree_id,
-                                   leaf_id) {
-
-  # Match tree id
-  single_tree_dt <- tree_dt[tree_index == tree_id, ]
-
-  # Get leaves
-  leaf_dt <- single_tree_dt[leaf_index == leaf_id, .(leaf_index, leaf_parent, leaf_value)]
-
-  # Get nodes
-  node_dt <- single_tree_dt[!is.na(split_index), .(split_index, split_feature, node_parent, internal_value)]
-
-  # Prepare sequences
-  feature_seq <- character(0L)
-  value_seq <- numeric(0L)
-
-  # Get to root from leaf
-  leaf_to_root <- function(parent_id, current_value) {
-
-    # Store value
-    value_seq <<- c(current_value, value_seq)
-
-    # Check for null parent id
-    if (!is.na(parent_id)) {
-
-      # Not null means existing node
-      this_node <- node_dt[split_index == parent_id, ]
-      feature_seq <<- c(this_node[["split_feature"]], feature_seq)
-      leaf_to_root(
-        parent_id = this_node[["node_parent"]]
-        , current_value = this_node[["internal_value"]]
-      )
-
-    }
-
-  }
-
-  # Perform leaf to root conversion
-  leaf_to_root(
-    parent_id = leaf_dt[["leaf_parent"]]
-    , current_value = leaf_dt[["leaf_value"]]
-  )
-
-  return(
-    data.table::data.table(
-      Feature = feature_seq
-      , Contribution = diff.default(value_seq)
-    )
-  )
-
-}
-
-#' @importFrom data.table := rbindlist setorder
-multiple.tree.interprete <- function(tree_dt,
-                                     tree_index,
-                                     leaf_index) {
-
-  # Apply each trees
-  interp_dt <- data.table::rbindlist(
-    l = mapply(
-      FUN = single.tree.interprete
-      , tree_id = tree_index
-      , leaf_id = leaf_index
-      , MoreArgs = list(
-        tree_dt = tree_dt
-      )
-      , SIMPLIFY = FALSE
-      , USE.NAMES = TRUE
-    )
-    , use.names = TRUE
-  )
-
-  interp_dt <- interp_dt[, .(Contribution = sum(Contribution)), by = "Feature"]
-
-  # Sort features in descending order by contribution
-  interp_dt[, abs_contribution := abs(Contribution)]
-  data.table::setorder(
-    x = interp_dt
-    , -abs_contribution
-  )
-
-  # Drop absolute value of contribution (only needed for sorting)
-  interp_dt[, abs_contribution := NULL]
-
-  return(interp_dt)
-
-}
-
-#' @importFrom data.table set setnames
-single.row.interprete <- function(tree_dt, num_class, tree_index_mat, leaf_index_mat) {
-
-  # Prepare vector list
-  tree_interpretation <- vector(mode = "list", length = num_class)
-
-  # Loop throughout each class
-  for (i in seq_len(num_class)) {
-
-    next_interp_dt <- multiple.tree.interprete(
-      tree_dt = tree_dt
-      , tree_index = tree_index_mat[, i]
-      , leaf_index = leaf_index_mat[, i]
-    )
-
-    if (num_class > 1L) {
-      data.table::setnames(
-        x = next_interp_dt
-        , old = "Contribution"
-        , new = paste("Class", i - 1L)
-      )
-    }
-
-    tree_interpretation[[i]] <- next_interp_dt
-
-  }
-
-  # Check for numbe rof classes larger than 1
-  if (num_class == 1L) {
-
-    # First interpretation element
-    tree_interpretation_dt <- tree_interpretation[[1L]]
-
-  } else {
-
-    # Full interpretation elements
-    tree_interpretation_dt <- Reduce(
-      f = function(x, y) {
-        merge(x, y, by = "Feature", all = TRUE)
-      }
-      , x = tree_interpretation
-    )
-
-    # Loop throughout each tree
-    for (j in 2L:ncol(tree_interpretation_dt)) {
-
-      data.table::set(
-        x = tree_interpretation_dt
-        , i = which(is.na(tree_interpretation_dt[[j]]))
-        , j = j
-        , value = 0.0
-      )
-
-    }
-
-  }
-
-  return(tree_interpretation_dt)
-}
diff --git a/R-package/R/lgb.model.dt.tree.R b/R-package/R/lgb.model.dt.tree.R
deleted file mode 100644
index 3385368c0..000000000
--- a/R-package/R/lgb.model.dt.tree.R
+++ /dev/null
@@ -1,180 +0,0 @@
-#' @name lgb.model.dt.tree
-#' @title Parse a LightGBM model json dump
-#' @description Parse a LightGBM model json dump into a \code{data.table} structure.
-#' @param model object of class \code{lgb.Booster}
-#' @param num_iteration number of iterations you want to predict with. NULL or
-#'                      <= 0 means use best iteration
-#' @return
-#' A \code{data.table} with detailed information about model trees' nodes and leafs.
-#'
-#' The columns of the \code{data.table} are:
-#'
-#' \itemize{
-#'  \item{\code{tree_index}: ID of a tree in a model (integer)}
-#'  \item{\code{split_index}: ID of a node in a tree (integer)}
-#'  \item{\code{split_feature}: for a node, it's a feature name (character);
-#'                              for a leaf, it simply labels it as \code{"NA"}}
-#'  \item{\code{node_parent}: ID of the parent node for current node (integer)}
-#'  \item{\code{leaf_index}: ID of a leaf in a tree (integer)}
-#'  \item{\code{leaf_parent}: ID of the parent node for current leaf (integer)}
-#'  \item{\code{split_gain}: Split gain of a node}
-#'  \item{\code{threshold}: Splitting threshold value of a node}
-#'  \item{\code{decision_type}: Decision type of a node}
-#'  \item{\code{default_left}: Determine how to handle NA value, TRUE -> Left, FALSE -> Right}
-#'  \item{\code{internal_value}: Node value}
-#'  \item{\code{internal_count}: The number of observation collected by a node}
-#'  \item{\code{leaf_value}: Leaf value}
-#'  \item{\code{leaf_count}: The number of observation collected by a leaf}
-#' }
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#'
-#' params <- list(
-#'   objective = "binary"
-#'   , learning_rate = 0.01
-#'   , num_leaves = 63L
-#'   , max_depth = -1L
-#'   , min_data_in_leaf = 1L
-#'   , min_sum_hessian_in_leaf = 1.0
-#' )
-#' model <- lgb.train(params, dtrain, 10L)
-#'
-#' tree_dt <- lgb.model.dt.tree(model)
-#' }
-#' @importFrom data.table := rbindlist
-#' @importFrom jsonlite fromJSON
-#' @export
-lgb.model.dt.tree <- function(model, num_iteration = NULL) {
-
-  # Dump json model first
-  json_model <- lgb.dump(booster = model, num_iteration = num_iteration)
-
-  # Parse json model second
-  parsed_json_model <- jsonlite::fromJSON(
-    txt = json_model
-    , simplifyVector = TRUE
-    , simplifyDataFrame = FALSE
-    , simplifyMatrix = FALSE
-    , flatten = FALSE
-  )
-
-  # Parse tree model third
-  tree_list <- lapply(parsed_json_model$tree_info, single.tree.parse)
-
-  # Combine into single data.table fourth
-  tree_dt <- data.table::rbindlist(l = tree_list, use.names = TRUE)
-
-  # Substitute feature index with the actual feature name
-
-  # Since the index comes from C++ (which is 0-indexed), be sure
-  # to add 1 (e.g. index 28 means the 29th feature in feature_names)
-  split_feature_indx <- tree_dt[, split_feature] + 1L
-
-  # Get corresponding feature names. Positions in split_feature_indx
-  # which are NA will result in an NA feature name
-  feature_names <- parsed_json_model$feature_names[split_feature_indx]
-  tree_dt[, split_feature := feature_names]
-
-  return(tree_dt)
-
-}
-
-
-#' @importFrom data.table := data.table rbindlist
-single.tree.parse <- function(lgb_tree) {
-
-  # Traverse tree function
-  pre_order_traversal <- function(env = NULL, tree_node_leaf, current_depth = 0L, parent_index = NA_integer_) {
-
-    if (is.null(env)) {
-      # Setup initial default data.table with default types
-      env <- new.env(parent = emptyenv())
-      env$single_tree_dt <- data.table::data.table(
-        tree_index = integer(0L)
-        , depth = integer(0L)
-        , split_index = integer(0L)
-        , split_feature = integer(0L)
-        , node_parent = integer(0L)
-        , leaf_index = integer(0L)
-        , leaf_parent = integer(0L)
-        , split_gain = numeric(0L)
-        , threshold = numeric(0L)
-        , decision_type = character(0L)
-        , default_left = character(0L)
-        , internal_value = integer(0L)
-        , internal_count = integer(0L)
-        , leaf_value = integer(0L)
-        , leaf_count = integer(0L)
-      )
-      # start tree traversal
-      pre_order_traversal(
-        env = env
-        , tree_node_leaf = tree_node_leaf
-        , current_depth = current_depth
-        , parent_index = parent_index
-      )
-    } else {
-
-      # Check if split index is not null in leaf
-      if (!is.null(tree_node_leaf$split_index)) {
-
-        # update data.table
-        env$single_tree_dt <- data.table::rbindlist(l = list(env$single_tree_dt,
-                                                             c(tree_node_leaf[c("split_index",
-                                                                                "split_feature",
-                                                                                "split_gain",
-                                                                                "threshold",
-                                                                                "decision_type",
-                                                                                "default_left",
-                                                                                "internal_value",
-                                                                                "internal_count")],
-                                                               "depth" = current_depth,
-                                                               "node_parent" = parent_index)),
-                                                    use.names = TRUE,
-                                                    fill = TRUE)
-
-        # Traverse tree again both left and right
-        pre_order_traversal(
-          env = env
-          , tree_node_leaf = tree_node_leaf$left_child
-          , current_depth = current_depth + 1L
-          , parent_index = tree_node_leaf$split_index
-        )
-        pre_order_traversal(
-          env = env
-          , tree_node_leaf = tree_node_leaf$right_child
-          , current_depth = current_depth + 1L
-          , parent_index = tree_node_leaf$split_index
-        )
-
-      } else if (!is.null(tree_node_leaf$leaf_index)) {
-
-        # update data.table
-        env$single_tree_dt <- data.table::rbindlist(l = list(env$single_tree_dt,
-                                                             c(tree_node_leaf[c("leaf_index",
-                                                                                "leaf_value",
-                                                                                "leaf_count")],
-                                                               "depth" = current_depth,
-                                                               "leaf_parent" = parent_index)),
-                                                    use.names = TRUE,
-                                                    fill = TRUE)
-
-      }
-
-    }
-    return(env$single_tree_dt)
-  }
-
-  # Traverse structure
-  single_tree_dt <- pre_order_traversal(tree_node_leaf = lgb_tree$tree_structure)
-
-  # Store index
-  single_tree_dt[, tree_index := lgb_tree$tree_index]
-
-  return(single_tree_dt)
-
-}
diff --git a/R-package/R/lgb.plot.importance.R b/R-package/R/lgb.plot.importance.R
deleted file mode 100644
index dfa9a138e..000000000
--- a/R-package/R/lgb.plot.importance.R
+++ /dev/null
@@ -1,96 +0,0 @@
-#' @name lgb.plot.importance
-#' @title Plot feature importance as a bar graph
-#' @description Plot previously calculated feature importance: Gain, Cover and Frequency, as a bar graph.
-#' @param tree_imp a \code{data.table} returned by \code{\link{lgb.importance}}.
-#' @param top_n maximal number of top features to include into the plot.
-#' @param measure the name of importance measure to plot, can be "Gain", "Cover" or "Frequency".
-#' @param left_margin (base R barplot) allows to adjust the left margin size to fit feature names.
-#' @param cex (base R barplot) passed as \code{cex.names} parameter to \code{\link[graphics]{barplot}}.
-#'            Set a number smaller than 1.0 to make the bar labels smaller than R's default and values
-#'            greater than 1.0 to make them larger.
-#'
-#' @details
-#' The graph represents each feature as a horizontal bar of length proportional to the defined importance of a feature.
-#' Features are shown ranked in a decreasing importance order.
-#'
-#' @return
-#' The \code{lgb.plot.importance} function creates a \code{barplot}
-#' and silently returns a processed data.table with \code{top_n} features sorted by defined importance.
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#'
-#' params <- list(
-#'     objective = "binary"
-#'     , learning_rate = 0.1
-#'     , min_data_in_leaf = 1L
-#'     , min_sum_hessian_in_leaf = 1.0
-#' )
-#'
-#' model <- lgb.train(
-#'     params = params
-#'     , data = dtrain
-#'     , nrounds = 5L
-#' )
-#'
-#' tree_imp <- lgb.importance(model, percentage = TRUE)
-#' lgb.plot.importance(tree_imp, top_n = 5L, measure = "Gain")
-#' }
-#' @importFrom graphics barplot par
-#' @export
-lgb.plot.importance <- function(tree_imp,
-                                top_n = 10L,
-                                measure = "Gain",
-                                left_margin = 10L,
-                                cex = NULL
-                                ) {
-
-  # Check for measurement (column names) correctness
-  measure <- match.arg(
-    measure
-    , choices = c("Gain", "Cover", "Frequency")
-    , several.ok = FALSE
-  )
-
-  # Get top N importance (defaults to 10)
-  top_n <- min(top_n, nrow(tree_imp))
-
-  # Parse importance
-  tree_imp <- tree_imp[order(abs(get(measure)), decreasing = TRUE), ][seq_len(top_n), ]
-
-  # Attempt to setup a correct cex
-  if (is.null(cex)) {
-    cex <- 2.5 / log2(1.0 + top_n)
-  }
-
-  # Refresh plot
-  op <- graphics::par(no.readonly = TRUE)
-  on.exit(graphics::par(op))
-
-  graphics::par(
-    mar = c(
-      op$mar[1L]
-      , left_margin
-      , op$mar[3L]
-      , op$mar[4L]
-    )
-  )
-
-  tree_imp[.N:1L,
-           graphics::barplot(
-               height = get(measure)
-               , names.arg = Feature
-               , horiz = TRUE
-               , border = NA
-               , main = "Feature Importance"
-               , xlab = measure
-               , cex.names = cex
-               , las = 1L
-           )]
-
-  return(invisible(tree_imp))
-
-}
diff --git a/R-package/R/lgb.plot.interpretation.R b/R-package/R/lgb.plot.interpretation.R
deleted file mode 100644
index 87c3e25b3..000000000
--- a/R-package/R/lgb.plot.interpretation.R
+++ /dev/null
@@ -1,161 +0,0 @@
-#' @name lgb.plot.interpretation
-#' @title Plot feature contribution as a bar graph
-#' @description Plot previously calculated feature contribution as a bar graph.
-#' @param tree_interpretation_dt a \code{data.table} returned by \code{\link{lgb.interprete}}.
-#' @param top_n maximal number of top features to include into the plot.
-#' @param cols the column numbers of layout, will be used only for multiclass classification feature contribution.
-#' @param left_margin (base R barplot) allows to adjust the left margin size to fit feature names.
-#' @param cex (base R barplot) passed as \code{cex.names} parameter to \code{barplot}.
-#'
-#' @details
-#' The graph represents each feature as a horizontal bar of length proportional to the defined
-#' contribution of a feature. Features are shown ranked in a decreasing contribution order.
-#'
-#' @return
-#' The \code{lgb.plot.interpretation} function creates a \code{barplot}.
-#'
-#' @examples
-#' \donttest{
-#' Logit <- function(x) {
-#'   log(x / (1.0 - x))
-#' }
-#' data(agaricus.train, package = "lightgbm")
-#' labels <- agaricus.train$label
-#' dtrain <- lgb.Dataset(
-#'   agaricus.train$data
-#'   , label = labels
-#' )
-#' setinfo(dtrain, "init_score", rep(Logit(mean(labels)), length(labels)))
-#'
-#' data(agaricus.test, package = "lightgbm")
-#'
-#' params <- list(
-#'   objective = "binary"
-#'   , learning_rate = 0.1
-#'   , max_depth = -1L
-#'   , min_data_in_leaf = 1L
-#'   , min_sum_hessian_in_leaf = 1.0
-#' )
-#' model <- lgb.train(
-#'   params = params
-#'   , data = dtrain
-#'   , nrounds = 5L
-#' )
-#'
-#' tree_interpretation <- lgb.interprete(
-#'   model = model
-#'   , data = agaricus.test$data
-#'   , idxset = 1L:5L
-#' )
-#' lgb.plot.interpretation(
-#'   tree_interpretation_dt = tree_interpretation[[1L]]
-#'   , top_n = 3L
-#' )
-#' }
-#' @importFrom data.table setnames
-#' @importFrom graphics barplot par
-#' @export
-lgb.plot.interpretation <- function(tree_interpretation_dt,
-                                    top_n = 10L,
-                                    cols = 1L,
-                                    left_margin = 10L,
-                                    cex = NULL) {
-
-  # Get number of columns
-  num_class <- ncol(tree_interpretation_dt) - 1L
-
-  # Refresh plot
-  op <- graphics::par(no.readonly = TRUE)
-  on.exit(graphics::par(op))
-
-  # Do some magic plotting
-  bottom_margin <- 3.0
-  top_margin <- 2.0
-  right_margin <- op$mar[4L]
-
-  graphics::par(
-    mar = c(
-      bottom_margin
-      , left_margin
-      , top_margin
-      , right_margin
-    )
-  )
-
-  # Check for number of classes
-  if (num_class == 1L) {
-
-    # Only one class, plot straight away
-    multiple.tree.plot.interpretation(
-      tree_interpretation = tree_interpretation_dt
-      , top_n = top_n
-      , title = NULL
-      , cex = cex
-    )
-
-  } else {
-
-    # More than one class, shape data first
-    layout_mat <- matrix(
-      seq.int(to = cols * ceiling(num_class / cols))
-      , ncol = cols
-      , nrow = ceiling(num_class / cols)
-    )
-
-    # Shape output
-    graphics::par(mfcol = c(nrow(layout_mat), ncol(layout_mat)))
-
-    # Loop throughout all classes
-    for (i in seq_len(num_class)) {
-
-      # Prepare interpretation, perform T, get the names, and plot straight away
-      plot_dt <- tree_interpretation_dt[, c(1L, i + 1L), with = FALSE]
-      data.table::setnames(
-        x = plot_dt
-        , old = names(plot_dt)
-        , new = c("Feature", "Contribution")
-      )
-      multiple.tree.plot.interpretation(
-        tree_interpretation = plot_dt
-        , top_n = top_n
-        , title = paste("Class", i - 1L)
-        , cex = cex
-      )
-
-    }
-  }
-  return(invisible(NULL))
-}
-
-#' @importFrom graphics barplot
-multiple.tree.plot.interpretation <- function(tree_interpretation,
-                                              top_n,
-                                              title,
-                                              cex) {
-
-  # Parse tree
-  tree_interpretation <- tree_interpretation[order(abs(Contribution), decreasing = TRUE), ][seq_len(min(top_n, .N)), ]
-
-  # Attempt to setup a correct cex
-  if (is.null(cex)) {
-    cex <- 2.5 / log2(1.0 + top_n)
-  }
-
-  # create plot
-  tree_interpretation[abs(Contribution) > 0.0, bar_color := "firebrick"]
-  tree_interpretation[Contribution == 0.0, bar_color := "steelblue"]
-  tree_interpretation[.N:1L,
-                      graphics::barplot(
-                          height = Contribution
-                          , names.arg = Feature
-                          , horiz = TRUE
-                          , col = bar_color
-                          , border = NA
-                          , main = title
-                          , cex.names = cex
-                          , las = 1L
-                      )]
-
-  return(invisible(NULL))
-
-}
diff --git a/R-package/R/lgb.train.R b/R-package/R/lgb.train.R
deleted file mode 100644
index c47d6ce69..000000000
--- a/R-package/R/lgb.train.R
+++ /dev/null
@@ -1,388 +0,0 @@
-#' @name lgb.train
-#' @title Main training logic for LightGBM
-#' @description Logic to train with LightGBM
-#' @inheritParams lgb_shared_params
-#' @param valids a list of \code{lgb.Dataset} objects, used for validation
-#' @param record Boolean, TRUE will record iteration message to \code{booster$record_evals}
-#' @param colnames feature names, if not null, will use this to overwrite the names in dataset
-#' @param categorical_feature categorical features. This can either be a character vector of feature
-#'                            names or an integer vector with the indices of the features (e.g.
-#'                            \code{c(1L, 10L)} to say "the first and tenth columns").
-#' @param callbacks List of callback functions that are applied at each iteration.
-#' @param reset_data Boolean, setting it to TRUE (not the default value) will transform the
-#'                   booster model into a predictor model which frees up memory and the
-#'                   original datasets
-#' @param ... other parameters, see \href{https://lightgbm.readthedocs.io/en/latest/Parameters.html}{
-#'            the "Parameters" section of the documentation} for more information. A few key parameters:
-#'            \itemize{
-#'                \item{\code{boosting}: Boosting type. \code{"gbdt"}, \code{"rf"}, \code{"dart"} or \code{"goss"}.}
-#'                \item{\code{num_leaves}: Maximum number of leaves in one tree.}
-#'                \item{\code{max_depth}: Limit the max depth for tree model. This is used to deal with
-#'                                 overfitting. Tree still grow by leaf-wise.}
-#'                \item{\code{num_threads}: Number of threads for LightGBM. For the best speed, set this to
-#'                             the number of real CPU cores(\code{parallel::detectCores(logical = FALSE)}),
-#'                             not the number of threads (most CPU using hyper-threading to generate 2 threads
-#'                             per CPU core).}
-#'            }
-#' @inheritSection lgb_shared_params Early Stopping
-#' @return a trained booster model \code{lgb.Booster}.
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data(agaricus.test, package = "lightgbm")
-#' test <- agaricus.test
-#' dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-#' params <- list(objective = "regression", metric = "l2")
-#' valids <- list(test = dtest)
-#' model <- lgb.train(
-#'   params = params
-#'   , data = dtrain
-#'   , nrounds = 5L
-#'   , valids = valids
-#'   , min_data = 1L
-#'   , learning_rate = 1.0
-#'   , early_stopping_rounds = 3L
-#' )
-#' }
-#' @export
-lgb.train <- function(params = list(),
-                      data,
-                      nrounds = 100L,
-                      valids = list(),
-                      obj = NULL,
-                      eval = NULL,
-                      verbose = 1L,
-                      record = TRUE,
-                      eval_freq = 1L,
-                      init_model = NULL,
-                      colnames = NULL,
-                      categorical_feature = NULL,
-                      early_stopping_rounds = NULL,
-                      callbacks = list(),
-                      reset_data = FALSE,
-                      ...) {
-
-  # validate inputs early to avoid unnecessary computation
-  if (nrounds <= 0L) {
-    stop("nrounds should be greater than zero")
-  }
-  if (!lgb.is.Dataset(x = data)) {
-    stop("lgb.train: data must be an lgb.Dataset instance")
-  }
-  if (length(valids) > 0L) {
-    if (!identical(class(valids), "list") || !all(vapply(valids, lgb.is.Dataset, logical(1L)))) {
-      stop("lgb.train: valids must be a list of lgb.Dataset elements")
-    }
-    evnames <- names(valids)
-    if (is.null(evnames) || !all(nzchar(evnames))) {
-      stop("lgb.train: each element of valids must have a name")
-    }
-  }
-
-  # Setup temporary variables
-  additional_params <- list(...)
-  params <- append(params, additional_params)
-  params$verbose <- verbose
-  params <- lgb.check.obj(params = params, obj = obj)
-  params <- lgb.check.eval(params = params, eval = eval)
-  fobj <- NULL
-  eval_functions <- list(NULL)
-
-  # set some parameters, resolving the way they were passed in with other parameters
-  # in `params`.
-  # this ensures that the model stored with Booster$save() correctly represents
-  # what was passed in
-  params <- lgb.check.wrapper_param(
-    main_param_name = "num_iterations"
-    , params = params
-    , alternative_kwarg_value = nrounds
-  )
-  params <- lgb.check.wrapper_param(
-    main_param_name = "early_stopping_round"
-    , params = params
-    , alternative_kwarg_value = early_stopping_rounds
-  )
-  early_stopping_rounds <- params[["early_stopping_round"]]
-
-  # Check for objective (function or not)
-  if (is.function(params$objective)) {
-    fobj <- params$objective
-    params$objective <- "NONE"
-  }
-
-  # If eval is a single function, store it as a 1-element list
-  # (for backwards compatibility). If it is a list of functions, store
-  # all of them. This makes it possible to pass any mix of strings like "auc"
-  # and custom functions to eval
-  if (is.function(eval)) {
-    eval_functions <- list(eval)
-  }
-  if (methods::is(eval, "list")) {
-    eval_functions <- Filter(
-      f = is.function
-      , x = eval
-    )
-  }
-
-  # Init predictor to empty
-  predictor <- NULL
-
-  # Check for boosting from a trained model
-  if (is.character(init_model)) {
-    predictor <- Predictor$new(init_model)
-  } else if (lgb.is.Booster(x = init_model)) {
-    predictor <- init_model$to_predictor()
-  }
-
-  # Set the iteration to start from / end to (and check for boosting from a trained model, again)
-  begin_iteration <- 1L
-  if (!is.null(predictor)) {
-    begin_iteration <- predictor$current_iter() + 1L
-  }
-  end_iteration <- begin_iteration + params[["num_iterations"]] - 1L
-
-  # pop interaction_constraints off of params. It needs some preprocessing on the
-  # R side before being passed into the Dataset object
-  interaction_constraints <- params[["interaction_constraints"]]
-  params["interaction_constraints"] <- NULL
-
-  # Construct datasets, if needed
-  data$update_params(params = params)
-  data$construct()
-
-  # Check interaction constraints
-  cnames <- NULL
-  if (!is.null(colnames)) {
-    cnames <- colnames
-  } else if (!is.null(data$get_colnames())) {
-    cnames <- data$get_colnames()
-  }
-  params[["interaction_constraints"]] <- lgb.check_interaction_constraints(
-    interaction_constraints = interaction_constraints
-    , column_names = cnames
-  )
-
-  # Update parameters with parsed parameters
-  data$update_params(params)
-
-  # Create the predictor set
-  data$.__enclos_env__$private$set_predictor(predictor)
-
-  # Write column names
-  if (!is.null(colnames)) {
-    data$set_colnames(colnames)
-  }
-
-  # Write categorical features
-  if (!is.null(categorical_feature)) {
-    data$set_categorical_feature(categorical_feature)
-  }
-
-  valid_contain_train <- FALSE
-  train_data_name <- "train"
-  reduced_valid_sets <- list()
-
-  # Parse validation datasets
-  if (length(valids) > 0L) {
-
-    # Loop through all validation datasets using name
-    for (key in names(valids)) {
-
-      # Use names to get validation datasets
-      valid_data <- valids[[key]]
-
-      # Check for duplicate train/validation dataset
-      if (identical(data, valid_data)) {
-        valid_contain_train <- TRUE
-        train_data_name <- key
-        next
-      }
-
-      # Update parameters, data
-      valid_data$update_params(params)
-      valid_data$set_reference(data)
-      reduced_valid_sets[[key]] <- valid_data
-
-    }
-
-  }
-
-  # Add printing log callback
-  if (verbose > 0L && eval_freq > 0L) {
-    callbacks <- add.cb(cb_list = callbacks, cb = cb.print.evaluation(period = eval_freq))
-  }
-
-  # Add evaluation log callback
-  if (record && length(valids) > 0L) {
-    callbacks <- add.cb(cb_list = callbacks, cb = cb.record.evaluation())
-  }
-
-  # Did user pass parameters that indicate they want to use early stopping?
-  using_early_stopping <- !is.null(early_stopping_rounds) && early_stopping_rounds > 0L
-
-  boosting_param_names <- .PARAMETER_ALIASES()[["boosting"]]
-  using_dart <- any(
-    sapply(
-      X = boosting_param_names
-      , FUN = function(param) {
-        identical(params[[param]], "dart")
-      }
-    )
-  )
-
-  # Cannot use early stopping with 'dart' boosting
-  if (using_dart) {
-    warning("Early stopping is not available in 'dart' mode.")
-    using_early_stopping <- FALSE
-
-    # Remove the cb.early.stop() function if it was passed in to callbacks
-    callbacks <- Filter(
-      f = function(cb_func) {
-        !identical(attr(cb_func, "name"), "cb.early.stop")
-      }
-      , x = callbacks
-    )
-  }
-
-  # If user supplied early_stopping_rounds, add the early stopping callback
-  if (using_early_stopping) {
-    callbacks <- add.cb(
-      cb_list = callbacks
-      , cb = cb.early.stop(
-        stopping_rounds = early_stopping_rounds
-        , first_metric_only = isTRUE(params[["first_metric_only"]])
-        , verbose = verbose
-      )
-    )
-  }
-
-  cb <- categorize.callbacks(cb_list = callbacks)
-
-  # Construct booster with datasets
-  booster <- Booster$new(params = params, train_set = data)
-  if (valid_contain_train) {
-    booster$set_train_data_name(name = train_data_name)
-  }
-
-  for (key in names(reduced_valid_sets)) {
-    booster$add_valid(data = reduced_valid_sets[[key]], name = key)
-  }
-
-  # Callback env
-  env <- CB_ENV$new()
-  env$model <- booster
-  env$begin_iteration <- begin_iteration
-  env$end_iteration <- end_iteration
-
-  # Start training model using number of iterations to start and end with
-  for (i in seq.int(from = begin_iteration, to = end_iteration)) {
-
-    # Overwrite iteration in environment
-    env$iteration <- i
-    env$eval_list <- list()
-
-    # Loop through "pre_iter" element
-    for (f in cb$pre_iter) {
-      f(env)
-    }
-
-    # Update one boosting iteration
-    booster$update(fobj = fobj)
-
-    # Prepare collection of evaluation results
-    eval_list <- list()
-
-    # Collection: Has validation dataset?
-    if (length(valids) > 0L) {
-
-      # Get evaluation results with passed-in functions
-      for (eval_function in eval_functions) {
-
-        # Validation has training dataset?
-        if (valid_contain_train) {
-          eval_list <- append(eval_list, booster$eval_train(feval = eval_function))
-        }
-
-        eval_list <- append(eval_list, booster$eval_valid(feval = eval_function))
-      }
-
-      # Calling booster$eval_valid() will get
-      # evaluation results with the metrics in params$metric by calling LGBM_BoosterGetEval_R",
-      # so need to be sure that gets called, which it wouldn't be above if no functions
-      # were passed in
-      if (length(eval_functions) == 0L) {
-        if (valid_contain_train) {
-          eval_list <- append(eval_list, booster$eval_train(feval = eval_function))
-        }
-        eval_list <- append(eval_list, booster$eval_valid(feval = eval_function))
-      }
-
-    }
-
-    # Write evaluation result in environment
-    env$eval_list <- eval_list
-
-    # Loop through env
-    for (f in cb$post_iter) {
-      f(env)
-    }
-
-    # Check for early stopping and break if needed
-    if (env$met_early_stop) break
-
-  }
-
-  # check if any valids were given other than the training data
-  non_train_valid_names <- names(valids)[!(names(valids) == train_data_name)]
-  first_valid_name <- non_train_valid_names[1L]
-
-  # When early stopping is not activated, we compute the best iteration / score ourselves by
-  # selecting the first metric and the first dataset
-  if (record && length(non_train_valid_names) > 0L && is.na(env$best_score)) {
-
-    # when using a custom eval function, the metric name is returned from the
-    # function, so figure it out from record_evals
-    if (!is.null(eval_functions[1L])) {
-      first_metric <- names(booster$record_evals[[first_valid_name]])[1L]
-    } else {
-      first_metric <- booster$.__enclos_env__$private$eval_names[1L]
-    }
-
-    .find_best <- which.min
-    if (isTRUE(env$eval_list[[1L]]$higher_better[1L])) {
-      .find_best <- which.max
-    }
-    booster$best_iter <- unname(
-      .find_best(
-        unlist(
-          booster$record_evals[[first_valid_name]][[first_metric]][[.EVAL_KEY()]]
-        )
-      )
-    )
-    booster$best_score <- booster$record_evals[[first_valid_name]][[first_metric]][[.EVAL_KEY()]][[booster$best_iter]]
-  }
-
-  # Check for booster model conversion to predictor model
-  if (reset_data) {
-
-    # Store temporarily model data elsewhere
-    booster_old <- list(
-      best_iter = booster$best_iter
-      , best_score = booster$best_score
-      , record_evals = booster$record_evals
-    )
-
-    # Reload model
-    booster <- lgb.load(model_str = booster$save_model_to_string())
-    booster$best_iter <- booster_old$best_iter
-    booster$best_score <- booster_old$best_score
-    booster$record_evals <- booster_old$record_evals
-
-  }
-
-  return(booster)
-
-}
diff --git a/R-package/R/lgb.unloader.R b/R-package/R/lgb.unloader.R
deleted file mode 100644
index a24f622cf..000000000
--- a/R-package/R/lgb.unloader.R
+++ /dev/null
@@ -1,73 +0,0 @@
-#' @name lgb.unloader
-#' @title Remove lightgbm and its objects from an environment
-#' @description Attempts to unload LightGBM packages so you can remove objects cleanly without
-#'              having to restart R. This is useful for instance if an object becomes stuck for no
-#'              apparent reason and you do not want to restart R to fix the lost object.
-#' @param restore Whether to reload \code{LightGBM} immediately after detaching from R.
-#'                Defaults to \code{TRUE} which means automatically reload \code{LightGBM} once
-#'                unloading is performed.
-#' @param wipe Whether to wipe all \code{lgb.Dataset} and \code{lgb.Booster} from the global
-#'             environment. Defaults to \code{FALSE} which means to not remove them.
-#' @param envir The environment to perform wiping on if \code{wipe == TRUE}. Defaults to
-#'              \code{.GlobalEnv} which is the global environment.
-#'
-#' @return NULL invisibly.
-#'
-#' @examples
-#' \donttest{
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data(agaricus.test, package = "lightgbm")
-#' test <- agaricus.test
-#' dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-#' params <- list(objective = "regression", metric = "l2")
-#' valids <- list(test = dtest)
-#' model <- lgb.train(
-#'   params = params
-#'   , data = dtrain
-#'   , nrounds = 5L
-#'   , valids = valids
-#'   , min_data = 1L
-#'   , learning_rate = 1.0
-#' )
-#'
-#' lgb.unloader(restore = FALSE, wipe = FALSE, envir = .GlobalEnv)
-#' rm(model, dtrain, dtest) # Not needed if wipe = TRUE
-#' gc() # Not needed if wipe = TRUE
-#'
-#' library(lightgbm)
-#' # Do whatever you want again with LightGBM without object clashing
-#' }
-#' @export
-lgb.unloader <- function(restore = TRUE, wipe = FALSE, envir = .GlobalEnv) {
-
-  # Unload package
-  try(detach("package:lightgbm", unload = TRUE), silent = TRUE)
-
-  # Should we wipe variables? (lgb.Booster, lgb.Dataset)
-  if (wipe) {
-    boosters <- Filter(
-      f = function(x) {
-        inherits(get(x, envir = envir), "lgb.Booster")
-      }
-      , x = ls(envir = envir)
-    )
-    datasets <- Filter(
-      f = function(x) {
-        inherits(get(x, envir = envir), "lgb.Dataset")
-      }
-      , x = ls(envir = envir)
-    )
-    rm(list = c(boosters, datasets), envir = envir)
-    gc(verbose = FALSE)
-  }
-
-  # Load package back?
-  if (restore) {
-    library(lightgbm)
-  }
-
-  return(invisible(NULL))
-
-}
diff --git a/R-package/R/lightgbm.R b/R-package/R/lightgbm.R
deleted file mode 100644
index e2df9063e..000000000
--- a/R-package/R/lightgbm.R
+++ /dev/null
@@ -1,263 +0,0 @@
-#' @name lgb_shared_params
-#' @title Shared parameter docs
-#' @description Parameter docs shared by \code{lgb.train}, \code{lgb.cv}, and \code{lightgbm}
-#' @param callbacks List of callback functions that are applied at each iteration.
-#' @param data a \code{lgb.Dataset} object, used for training. Some functions, such as \code{\link{lgb.cv}},
-#'             may allow you to pass other types of data like \code{matrix} and then separately supply
-#'             \code{label} as a keyword argument.
-#' @param early_stopping_rounds int. Activates early stopping. When this parameter is non-null,
-#'                              training will stop if the evaluation of any metric on any validation set
-#'                              fails to improve for \code{early_stopping_rounds} consecutive boosting rounds.
-#'                              If training stops early, the returned model will have attribute \code{best_iter}
-#'                              set to the iteration number of the best iteration.
-#' @param eval evaluation function(s). This can be a character vector, function, or list with a mixture of
-#'             strings and functions.
-#'
-#'             \itemize{
-#'                 \item{\bold{a. character vector}:
-#'                     If you provide a character vector to this argument, it should contain strings with valid
-#'                     evaluation metrics.
-#'                     See \href{https://lightgbm.readthedocs.io/en/latest/Parameters.html#metric}{
-#'                     The "metric" section of the documentation}
-#'                     for a list of valid metrics.
-#'                 }
-#'                 \item{\bold{b. function}:
-#'                      You can provide a custom evaluation function. This
-#'                      should accept the keyword arguments \code{preds} and \code{dtrain} and should return a named
-#'                      list with three elements:
-#'                      \itemize{
-#'                          \item{\code{name}: A string with the name of the metric, used for printing
-#'                              and storing results.
-#'                          }
-#'                          \item{\code{value}: A single number indicating the value of the metric for the
-#'                              given predictions and true values
-#'                          }
-#'                          \item{
-#'                              \code{higher_better}: A boolean indicating whether higher values indicate a better fit.
-#'                              For example, this would be \code{FALSE} for metrics like MAE or RMSE.
-#'                          }
-#'                      }
-#'                 }
-#'                 \item{\bold{c. list}:
-#'                     If a list is given, it should only contain character vectors and functions.
-#'                     These should follow the requirements from the descriptions above.
-#'                 }
-#'             }
-#' @param eval_freq evaluation output frequency, only effect when verbose > 0
-#' @param init_model path of model file of \code{lgb.Booster} object, will continue training from this model
-#' @param nrounds number of training rounds
-#' @param obj objective function, can be character or custom objective function. Examples include
-#'            \code{regression}, \code{regression_l1}, \code{huber},
-#'            \code{binary}, \code{lambdarank}, \code{multiclass}, \code{multiclass}
-#' @param params a list of parameters. See \href{https://lightgbm.readthedocs.io/en/latest/Parameters.html}{
-#'               the "Parameters" section of the documentation} for a list of parameters and valid values.
-#' @param verbose verbosity for output, if <= 0, also will disable the print of evaluation during training
-#' @section Early Stopping:
-#'
-#'          "early stopping" refers to stopping the training process if the model's performance on a given
-#'          validation set does not improve for several consecutive iterations.
-#'
-#'          If multiple arguments are given to \code{eval}, their order will be preserved. If you enable
-#'          early stopping by setting \code{early_stopping_rounds} in \code{params}, by default all
-#'          metrics will be considered for early stopping.
-#'
-#'          If you want to only consider the first metric for early stopping, pass
-#'          \code{first_metric_only = TRUE} in \code{params}. Note that if you also specify \code{metric}
-#'          in \code{params}, that metric will be considered the "first" one. If you omit \code{metric},
-#'          a default metric will be used based on your choice for the parameter \code{obj} (keyword argument)
-#'          or \code{objective} (passed into \code{params}).
-#' @keywords internal
-NULL
-
-#' @name lightgbm
-#' @title Train a LightGBM model
-#' @description Simple interface for training a LightGBM model.
-#' @inheritParams lgb_shared_params
-#' @param label Vector of labels, used if \code{data} is not an \code{\link{lgb.Dataset}}
-#' @param weight vector of response values. If not NULL, will set to dataset
-#' @param save_name File name to use when writing the trained model to disk. Should end in ".model".
-#' @param ... Additional arguments passed to \code{\link{lgb.train}}. For example
-#'     \itemize{
-#'        \item{\code{valids}: a list of \code{lgb.Dataset} objects, used for validation}
-#'        \item{\code{obj}: objective function, can be character or custom objective function. Examples include
-#'                   \code{regression}, \code{regression_l1}, \code{huber},
-#'                    \code{binary}, \code{lambdarank}, \code{multiclass}, \code{multiclass}}
-#'        \item{\code{eval}: evaluation function, can be (a list of) character or custom eval function}
-#'        \item{\code{record}: Boolean, TRUE will record iteration message to \code{booster$record_evals}}
-#'        \item{\code{colnames}: feature names, if not null, will use this to overwrite the names in dataset}
-#'        \item{\code{categorical_feature}: categorical features. This can either be a character vector of feature
-#'                            names or an integer vector with the indices of the features (e.g. \code{c(1L, 10L)} to
-#'                            say "the first and tenth columns").}
-#'        \item{\code{reset_data}: Boolean, setting it to TRUE (not the default value) will transform the booster model
-#'                          into a predictor model which frees up memory and the original datasets}
-#'         \item{\code{boosting}: Boosting type. \code{"gbdt"}, \code{"rf"}, \code{"dart"} or \code{"goss"}.}
-#'         \item{\code{num_leaves}: Maximum number of leaves in one tree.}
-#'         \item{\code{max_depth}: Limit the max depth for tree model. This is used to deal with
-#'                          overfit when #data is small. Tree still grow by leaf-wise.}
-#'          \item{\code{num_threads}: Number of threads for LightGBM. For the best speed, set this to
-#'                             the number of real CPU cores(\code{parallel::detectCores(logical = FALSE)}),
-#'                             not the number of threads (most CPU using hyper-threading to generate 2 threads
-#'                             per CPU core).}
-#'     }
-#' @inheritSection lgb_shared_params Early Stopping
-#' @return a trained \code{lgb.Booster}
-#' @export
-lightgbm <- function(data,
-                     label = NULL,
-                     weight = NULL,
-                     params = list(),
-                     nrounds = 100L,
-                     verbose = 1L,
-                     eval_freq = 1L,
-                     early_stopping_rounds = NULL,
-                     save_name = "lightgbm.model",
-                     init_model = NULL,
-                     callbacks = list(),
-                     ...) {
-
-  # validate inputs early to avoid unnecessary computation
-  if (nrounds <= 0L) {
-    stop("nrounds should be greater than zero")
-  }
-
-  # Set data to a temporary variable
-  dtrain <- data
-
-  # Check whether data is lgb.Dataset, if not then create lgb.Dataset manually
-  if (!lgb.is.Dataset(x = dtrain)) {
-    dtrain <- lgb.Dataset(data = data, label = label, weight = weight)
-  }
-
-  train_args <- list(
-    "params" = params
-    , "data" = dtrain
-    , "nrounds" = nrounds
-    , "verbose" = verbose
-    , "eval_freq" = eval_freq
-    , "early_stopping_rounds" = early_stopping_rounds
-    , "init_model" = init_model
-    , "callbacks" = callbacks
-  )
-  train_args <- append(train_args, list(...))
-
-  if (! "valids" %in% names(train_args)) {
-    train_args[["valids"]] <- list()
-  }
-
-  # Set validation as oneself
-  if (verbose > 0L) {
-    train_args[["valids"]][["train"]] <- dtrain
-  }
-
-  # Train a model using the regular way
-  bst <- do.call(
-    what = lgb.train
-    , args = train_args
-  )
-
-  # Store model under a specific name
-  bst$save_model(filename = save_name)
-
-  return(bst)
-}
-
-#' @name agaricus.train
-#' @title Training part from Mushroom Data Set
-#' @description This data set is originally from the Mushroom data set,
-#'              UCI Machine Learning Repository.
-#'              This data set includes the following fields:
-#'
-#'               \itemize{
-#'                   \item{\code{label}: the label for each record}
-#'                   \item{\code{data}: a sparse Matrix of \code{dgCMatrix} class, with 126 columns.}
-#'                }
-#'
-#' @references
-#' https://archive.ics.uci.edu/ml/datasets/Mushroom
-#'
-#' Bache, K. & Lichman, M. (2013). UCI Machine Learning Repository
-#' [http://archive.ics.uci.edu/ml]. Irvine, CA: University of California,
-#' School of Information and Computer Science.
-#'
-#' @docType data
-#' @keywords datasets
-#' @usage data(agaricus.train)
-#' @format A list containing a label vector, and a dgCMatrix object with 6513
-#' rows and 127 variables
-NULL
-
-#' @name agaricus.test
-#' @title Test part from Mushroom Data Set
-#' @description This data set is originally from the Mushroom data set,
-#'              UCI Machine Learning Repository.
-#'              This data set includes the following fields:
-#'
-#'              \itemize{
-#'                  \item{\code{label}: the label for each record}
-#'                  \item{\code{data}: a sparse Matrix of \code{dgCMatrix} class, with 126 columns.}
-#'              }
-#' @references
-#' https://archive.ics.uci.edu/ml/datasets/Mushroom
-#'
-#' Bache, K. & Lichman, M. (2013). UCI Machine Learning Repository
-#' [http://archive.ics.uci.edu/ml]. Irvine, CA: University of California,
-#' School of Information and Computer Science.
-#'
-#' @docType data
-#' @keywords datasets
-#' @usage data(agaricus.test)
-#' @format A list containing a label vector, and a dgCMatrix object with 1611
-#' rows and 126 variables
-NULL
-
-#' @name bank
-#' @title Bank Marketing Data Set
-#' @description This data set is originally from the Bank Marketing data set,
-#'              UCI Machine Learning Repository.
-#'
-#'              It contains only the following: bank.csv with 10% of the examples and 17 inputs,
-#'              randomly selected from 3 (older version of this dataset with less inputs).
-#'
-#' @references
-#' http://archive.ics.uci.edu/ml/datasets/Bank+Marketing
-#'
-#' S. Moro, P. Cortez and P. Rita. (2014)
-#' A Data-Driven Approach to Predict the Success of Bank Telemarketing. Decision Support Systems
-#'
-#' @docType data
-#' @keywords datasets
-#' @usage data(bank)
-#' @format A data.table with 4521 rows and 17 variables
-NULL
-
-# Various imports
-#' @import methods
-#' @importFrom Matrix Matrix
-#' @importFrom R6 R6Class
-#' @useDynLib lib_lightgbm , .registration = TRUE
-NULL
-
-# Suppress false positive warnings from R CMD CHECK about
-# "unrecognized global variable"
-globalVariables(c(
-    "."
-    , ".N"
-    , ".SD"
-    , "abs_contribution"
-    , "bar_color"
-    , "Contribution"
-    , "Cover"
-    , "Feature"
-    , "Frequency"
-    , "Gain"
-    , "internal_count"
-    , "internal_value"
-    , "leaf_index"
-    , "leaf_parent"
-    , "leaf_value"
-    , "node_parent"
-    , "split_feature"
-    , "split_gain"
-    , "split_index"
-    , "tree_index"
-))
diff --git a/R-package/R/metrics.R b/R-package/R/metrics.R
deleted file mode 100644
index e7099e948..000000000
--- a/R-package/R/metrics.R
+++ /dev/null
@@ -1,37 +0,0 @@
-# [description] List of metrics known to LightGBM. The most up to date list can be found
-#               at https://lightgbm.readthedocs.io/en/latest/Parameters.html#metric-parameters
-#
-# [return] A named logical vector, where each key is a metric name and each value is a boolean.
-#          TRUE if higher values of the metric are desirable, FALSE if lower values are desirable.
-#          Note that only the 'main' metrics are stored here, not aliases, since only the 'main' metrics
-#          are returned from the C++ side. For example, if you use `metric = "mse"` in your code,
-#          the metric name `"l2"` will be returned.
-.METRICS_HIGHER_BETTER <- function() {
-    return(
-        c(
-            "l1" = FALSE
-            , "l2" = FALSE
-            , "mape" = FALSE
-            , "rmse" = FALSE
-            , "quantile" = FALSE
-            , "huber" = FALSE
-            , "fair" = FALSE
-            , "poisson" = FALSE
-            , "gamma" = FALSE
-            , "gamma_deviance" = FALSE
-            , "tweedie" = FALSE
-            , "ndcg" = TRUE
-            , "map" = TRUE
-            , "auc" = TRUE
-            , "average_precision" = TRUE
-            , "binary_logloss" = FALSE
-            , "binary_error" = FALSE
-            , "auc_mu" = TRUE
-            , "multi_logloss" = FALSE
-            , "multi_error" = FALSE
-            , "cross_entropy" = FALSE
-            , "cross_entropy_lambda" = FALSE
-            , "kullback_leibler" = FALSE
-        )
-    )
-}
diff --git a/R-package/R/readRDS.lgb.Booster.R b/R-package/R/readRDS.lgb.Booster.R
deleted file mode 100644
index df48d4807..000000000
--- a/R-package/R/readRDS.lgb.Booster.R
+++ /dev/null
@@ -1,59 +0,0 @@
-#' @name readRDS.lgb.Booster
-#' @title readRDS for \code{lgb.Booster} models
-#' @description Attempts to load a model stored in a \code{.rds} file, using \code{\link[base]{readRDS}}
-#' @param file a connection or the name of the file where the R object is saved to or read from.
-#' @param refhook a hook function for handling reference objects.
-#'
-#' @return \code{lgb.Booster}
-#'
-#' @examples
-#' \donttest{
-#' library(lightgbm)
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data(agaricus.test, package = "lightgbm")
-#' test <- agaricus.test
-#' dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-#' params <- list(objective = "regression", metric = "l2")
-#' valids <- list(test = dtest)
-#' model <- lgb.train(
-#'   params = params
-#'   , data = dtrain
-#'   , nrounds = 10L
-#'   , valids = valids
-#'   , min_data = 1L
-#'   , learning_rate = 1.0
-#'   , early_stopping_rounds = 5L
-#' )
-#' model_file <- tempfile(fileext = ".rds")
-#' saveRDS.lgb.Booster(model, model_file)
-#' new_model <- readRDS.lgb.Booster(model_file)
-#' }
-#' @export
-readRDS.lgb.Booster <- function(file, refhook = NULL) {
-
-  object <- readRDS(file = file, refhook = refhook)
-
-  # Check if object has the model stored
-  if (!is.na(object$raw)) {
-
-    # Create temporary model for the model loading
-    object2 <- lgb.load(model_str = object$raw)
-
-    # Restore best iteration and recorded evaluations
-    object2$best_iter <- object$best_iter
-    object2$record_evals <- object$record_evals
-    object2$params <- object$params
-
-    # Return newly loaded object
-    return(object2)
-
-  } else {
-
-    # Return RDS loaded object
-    return(object)
-
-  }
-
-}
diff --git a/R-package/R/saveRDS.lgb.Booster.R b/R-package/R/saveRDS.lgb.Booster.R
deleted file mode 100644
index 64b1f78ec..000000000
--- a/R-package/R/saveRDS.lgb.Booster.R
+++ /dev/null
@@ -1,86 +0,0 @@
-#' @name saveRDS.lgb.Booster
-#' @title saveRDS for \code{lgb.Booster} models
-#' @description Attempts to save a model using RDS. Has an additional parameter (\code{raw})
-#'              which decides whether to save the raw model or not.
-#' @param object \code{lgb.Booster} object to serialize.
-#' @param file a connection or the name of the file where the R object is saved to or read from.
-#' @param ascii a logical. If TRUE or NA, an ASCII representation is written; otherwise (default),
-#'              a binary one is used. See the comments in the help for save.
-#' @param version the workspace format version to use. \code{NULL} specifies the current default
-#'                version (2). Versions prior to 2 are not supported, so this will only be relevant
-#'                when there are later versions.
-#' @param compress a logical specifying whether saving to a named file is to use "gzip" compression,
-#'                 or one of \code{"gzip"}, \code{"bzip2"} or \code{"xz"} to indicate the type of
-#'                 compression to be used. Ignored if file is a connection.
-#' @param refhook a hook function for handling reference objects.
-#' @param raw whether to save the model in a raw variable or not, recommended to leave it to \code{TRUE}.
-#'
-#' @return NULL invisibly.
-#'
-#' @examples
-#' \donttest{
-#' library(lightgbm)
-#' data(agaricus.train, package = "lightgbm")
-#' train <- agaricus.train
-#' dtrain <- lgb.Dataset(train$data, label = train$label)
-#' data(agaricus.test, package = "lightgbm")
-#' test <- agaricus.test
-#' dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-#' params <- list(objective = "regression", metric = "l2")
-#' valids <- list(test = dtest)
-#' model <- lgb.train(
-#'     params = params
-#'     , data = dtrain
-#'     , nrounds = 10L
-#'     , valids = valids
-#'     , min_data = 1L
-#'     , learning_rate = 1.0
-#'     , early_stopping_rounds = 5L
-#' )
-#' model_file <- tempfile(fileext = ".rds")
-#' saveRDS.lgb.Booster(model, model_file)
-#' }
-#' @export
-saveRDS.lgb.Booster <- function(object,
-                                file,
-                                ascii = FALSE,
-                                version = NULL,
-                                compress = TRUE,
-                                refhook = NULL,
-                                raw = TRUE) {
-
-  # Check if object has a raw value (and if the user wants to store the raw)
-  if (is.na(object$raw) && raw) {
-
-    object$save()
-
-    saveRDS(
-      object
-      , file = file
-      , ascii = ascii
-      , version = version
-      , compress = compress
-      , refhook = refhook
-    )
-
-    # Free model from memory
-    object$raw <- NA
-
-    return(invisible(NULL))
-
-  } else {
-
-    saveRDS(
-      object
-      , file = file
-      , ascii = ascii
-      , version = version
-      , compress = compress
-      , refhook = refhook
-    )
-
-    return(invisible(NULL))
-
-  }
-
-}
diff --git a/R-package/R/utils.R b/R-package/R/utils.R
deleted file mode 100644
index 013e2d4a9..000000000
--- a/R-package/R/utils.R
+++ /dev/null
@@ -1,329 +0,0 @@
-lgb.is.Booster <- function(x) {
-  return(lgb.check.r6.class(object = x, name = "lgb.Booster"))
-}
-
-lgb.is.Dataset <- function(x) {
-  return(lgb.check.r6.class(object = x, name = "lgb.Dataset"))
-}
-
-lgb.null.handle <- function() {
-  if (.Machine$sizeof.pointer == 8L) {
-    return(NA_real_)
-  } else {
-    return(NA_integer_)
-  }
-}
-
-lgb.is.null.handle <- function(x) {
-  return(is.null(x) || is.na(x))
-}
-
-lgb.encode.char <- function(arr, len) {
-  if (!is.raw(arr)) {
-    stop("lgb.encode.char: Can only encode from raw type")
-  }
-  return(rawToChar(arr[seq_len(len)]))
-}
-
-# [description] Get the most recent error stored on the C++ side and raise it
-#               as an R error.
-lgb.last_error <- function() {
-  err_msg <- .Call(
-    LGBM_GetLastError_R
-  )
-  stop("api error: ", err_msg)
-  return(invisible(NULL))
-}
-lgb.params2str <- function(params, ...) {
-
-  # Check for a list as input
-  if (!identical(class(params), "list")) {
-    stop("params must be a list")
-  }
-
-  # Split parameter names
-  names(params) <- gsub("\\.", "_", names(params))
-
-  # Merge parameters from the params and the dots-expansion
-  dot_params <- list(...)
-  names(dot_params) <- gsub("\\.", "_", names(dot_params))
-
-  # Check for identical parameters
-  if (length(intersect(names(params), names(dot_params))) > 0L) {
-    stop(
-      "Same parameters in "
-      , sQuote("params")
-      , " and in the call are not allowed. Please check your "
-      , sQuote("params")
-      , " list"
-    )
-  }
-
-  # Merge parameters
-  params <- c(params, dot_params)
-
-  # Setup temporary variable
-  ret <- list()
-
-  # Perform key value join
-  for (key in names(params)) {
-
-    # If a parameter has multiple values, join those values together with commas.
-    # trimws() is necessary because format() will pad to make strings the same width
-    val <- paste0(
-      trimws(
-        format(
-          x = params[[key]]
-          , scientific = FALSE
-        )
-      )
-      , collapse = ","
-    )
-    if (nchar(val) <= 0L) next # Skip join
-
-    # Join key value
-    pair <- paste0(c(key, val), collapse = "=")
-    ret <- c(ret, pair)
-
-  }
-
-  # Check ret length
-  if (length(ret) == 0L) {
-    return("")
-  }
-
-  return(paste0(ret, collapse = " "))
-
-}
-
-lgb.check_interaction_constraints <- function(interaction_constraints, column_names) {
-
-  # Convert interaction constraints to feature numbers
-  string_constraints <- list()
-
-  if (!is.null(interaction_constraints)) {
-
-    if (!methods::is(interaction_constraints, "list")) {
-        stop("interaction_constraints must be a list")
-    }
-    if (!all(sapply(interaction_constraints, function(x) {is.character(x) || is.numeric(x)}))) {
-        stop("every element in interaction_constraints must be a character vector or numeric vector")
-    }
-
-    for (constraint in interaction_constraints) {
-
-      # Check for character name
-      if (is.character(constraint)) {
-
-          constraint_indices <- as.integer(match(constraint, column_names) - 1L)
-
-          # Provided indices, but some indices are not existing?
-          if (sum(is.na(constraint_indices)) > 0L) {
-            stop(
-              "supplied an unknown feature in interaction_constraints "
-              , sQuote(constraint[is.na(constraint_indices)])
-            )
-          }
-
-        } else {
-
-          # Check that constraint indices are at most number of features
-          if (max(constraint) > length(column_names)) {
-            stop(
-              "supplied a too large value in interaction_constraints: "
-              , max(constraint)
-              , " but only "
-              , length(column_names)
-              , " features"
-            )
-          }
-
-          # Store indices as [0, n-1] indexed instead of [1, n] indexed
-          constraint_indices <- as.integer(constraint - 1L)
-
-        }
-
-        # Convert constraint to string
-        constraint_string <- paste0("[", paste0(constraint_indices, collapse = ","), "]")
-        string_constraints <- append(string_constraints, constraint_string)
-    }
-
-  }
-
-  return(string_constraints)
-
-}
-
-
-lgb.check.r6.class <- function(object, name) {
-
-  # Check for non-existence of R6 class or named class
-  return(all(c("R6", name) %in% class(object)))
-
-}
-
-lgb.check.obj <- function(params, obj) {
-
-  # List known objectives in a vector
-  OBJECTIVES <- c(
-    "regression"
-    , "regression_l1"
-    , "regression_l2"
-    , "mean_squared_error"
-    , "mse"
-    , "l2_root"
-    , "root_mean_squared_error"
-    , "rmse"
-    , "mean_absolute_error"
-    , "mae"
-    , "quantile"
-    , "huber"
-    , "fair"
-    , "poisson"
-    , "binary"
-    , "lambdarank"
-    , "multiclass"
-    , "softmax"
-    , "multiclassova"
-    , "multiclass_ova"
-    , "ova"
-    , "ovr"
-    , "xentropy"
-    , "cross_entropy"
-    , "xentlambda"
-    , "cross_entropy_lambda"
-    , "mean_absolute_percentage_error"
-    , "mape"
-    , "gamma"
-    , "tweedie"
-    , "rank_xendcg"
-    , "xendcg"
-    , "xe_ndcg"
-    , "xe_ndcg_mart"
-    , "xendcg_mart"
-  )
-
-  # Check whether the objective is empty or not, and take it from params if needed
-  if (!is.null(obj)) {
-    params$objective <- obj
-  }
-
-  # Check whether the objective is a character
-  if (is.character(params$objective)) {
-
-    # If the objective is a character, check if it is a known objective
-    if (!(params$objective %in% OBJECTIVES)) {
-
-      stop("lgb.check.obj: objective name error should be one of (", paste0(OBJECTIVES, collapse = ", "), ")")
-
-    }
-
-  } else if (!is.function(params$objective)) {
-
-    stop("lgb.check.obj: objective should be a character or a function")
-
-  }
-
-  return(params)
-
-}
-
-# [description]
-#     Take any character values from eval and store them in params$metric.
-#     This has to account for the fact that `eval` could be a character vector,
-#     a function, a list of functions, or a list with a mix of strings and
-#     functions
-lgb.check.eval <- function(params, eval) {
-
-  if (is.null(params$metric)) {
-    params$metric <- list()
-  } else if (is.character(params$metric)) {
-    params$metric <- as.list(params$metric)
-  }
-
-  # if 'eval' is a character vector or list, find the character
-  # elements and add them to 'metric'
-  if (!is.function(eval)) {
-    for (i in seq_along(eval)) {
-      element <- eval[[i]]
-      if (is.character(element)) {
-        params$metric <- append(params$metric, element)
-      }
-    }
-  }
-
-  # If more than one character metric was given, then "None" should
-  # not be included
-  if (length(params$metric) > 1L) {
-    params$metric <- Filter(
-        f = function(metric) {
-          !(metric %in% .NO_METRIC_STRINGS())
-        }
-        , x = params$metric
-    )
-  }
-
-  # duplicate metrics should be filtered out
-  params$metric <- as.list(unique(unlist(params$metric)))
-
-  return(params)
-}
-
-
-# [description]
-#
-#     Resolve differences between passed-in keyword arguments, parameters,
-#     and parameter aliases. This function exists because some functions in the
-#     package take in parameters through their own keyword arguments other than
-#     the `params` list.
-#
-#     If the same underlying parameter is provided multiple
-#     ways, the first item in this list is used:
-#
-#         1. the main (non-alias) parameter found in `params`
-#         2. the first alias of that parameter found in `params`
-#         3. the keyword argument passed in
-#
-#     For example, "num_iterations" can also be provided to lgb.train()
-#     via keyword "nrounds". lgb.train() will choose one value for this parameter
-#     based on the first match in this list:
-#
-#         1. params[["num_iterations]]
-#         2. the first alias of "num_iterations" found in params
-#         3. the nrounds keyword argument
-#
-#     If multiple aliases are found in `params` for the same parameter, they are
-#     all removed before returning `params`.
-#
-# [return]
-#     params with num_iterations set to the chosen value, and other aliases
-#     of num_iterations removed
-lgb.check.wrapper_param <- function(main_param_name, params, alternative_kwarg_value) {
-
-  aliases <- .PARAMETER_ALIASES()[[main_param_name]]
-  aliases_provided <- names(params)[names(params) %in% aliases]
-  aliases_provided <- aliases_provided[aliases_provided != main_param_name]
-
-  # prefer the main parameter
-  if (!is.null(params[[main_param_name]])) {
-    for (param in aliases_provided) {
-      params[[param]] <- NULL
-    }
-    return(params)
-  }
-
-  # if the main parameter wasn't proovided, prefer the first alias
-  if (length(aliases_provided) > 0L) {
-    first_param <- aliases_provided[1L]
-    params[[main_param_name]] <- params[[first_param]]
-    for (param in aliases_provided) {
-      params[[param]] <- NULL
-    }
-    return(params)
-  }
-
-  # if not provided in params at all, use the alternative value provided
-  # through a keyword argument from lgb.train(), lgb.cv(), etc.
-  params[[main_param_name]] <- alternative_kwarg_value
-  return(params)
-}
diff --git a/R-package/README.md b/R-package/README.md
deleted file mode 100644
index 3e4c6f50e..000000000
--- a/R-package/README.md
+++ /dev/null
@@ -1,434 +0,0 @@
-# LightGBM R-package
-
-[![CRAN Version](https://www.r-pkg.org/badges/version/lightgbm)](https://cran.r-project.org/package=lightgbm)
-[![Downloads](https://cranlogs.r-pkg.org/badges/grand-total/lightgbm)](https://cran.r-project.org/package=lightgbm)
-[![API Docs](https://readthedocs.org/projects/lightgbm/badge/?version=latest)](https://lightgbm.readthedocs.io/en/latest/R/reference/)
-
-<img src="man/figures/logo.svg" align="right" alt="" width="175" />
-
-### Contents
-
-* [Installation](#installation)
-    - [Installing the CRAN Package](#installing-the-cran-package)
-    - [Installing from Source with CMake](#install)
-    - [Installing a GPU-enabled Build](#installing-a-gpu-enabled-build)
-    - [Installing Precompiled Binaries](#installing-precompiled-binaries)
-    - [Installing from a Pre-compiled lib_lightgbm](#lib_lightgbm)
-* [Examples](#examples)
-* [Testing](#testing)
-* [Preparing a CRAN Package](#preparing-a-cran-package)
-* [External Repositories](#external-unofficial-repositories)
-* [Known Issues](#known-issues)
-
-Installation
-------------
-
-For the easiest installation, go to ["Installing the CRAN package"](#installing-the-cran-package).
-
-If you experience any issues with that, try ["Installing from Source with CMake"](#install). This can produce a more efficient version of the library on Windows systems with Visual Studio.
-
-To build a GPU-enabled version of the package, follow the steps in ["Installing a GPU-enabled Build"](#installing-a-gpu-enabled-build).
-
-If any of the above options do not work for you or do not meet your needs, please let the maintainers know by [opening an issue](https://github.com/microsoft/LightGBM/issues).
-
-When your package installation is done, you can check quickly if your LightGBM R-package is working by running the following:
-
-```r
-library(lightgbm)
-data(agaricus.train, package='lightgbm')
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-model <- lgb.cv(
-    params = list(
-        objective = "regression"
-        , metric = "l2"
-    )
-    , data = dtrain
-)
-```
-
-### Installing the CRAN package
-
-`{lightgbm}` is [available on CRAN](https://cran.r-project.org/package=lightgbm), and can be installed with the following R code.
-
-```r
-install.packages("lightgbm", repos = "https://cran.r-project.org")
-```
-
-This is the easiest way to install `{lightgbm}`. It does not require `CMake` or `Visual Studio`, and  should work well on many different operating systems and compilers.
-
-Each CRAN package is also available on [LightGBM releases](https://github.com/microsoft/LightGBM/releases), with a name like `lightgbm-{VERSION}-r-cran.tar.gz`.
-
-#### Custom Installation (Linux, Mac)
-
-The steps above should work on most systems, but users with highly-customized environments might want to change how R builds packages from source.
-
-To change the compiler used when installing the CRAN package, you can create a file `~/.R/Makevars` which overrides `CC` (`C` compiler) and `CXX` (`C++` compiler).
-
-For example, to use `gcc` instead of `clang` on Mac, you could use something like the following:
-
-```make
-# ~/.R/Makevars
-CC=gcc-8
-CXX=g++-8
-CXX11=g++-8
-```
-
-### Installing from Source with CMake <a name="install"></a>
-
-You need to install git and [CMake](https://cmake.org/) first.
-
-Note: this method is only supported on 64-bit systems. If you need to run LightGBM on 32-bit Windows (i386), follow the instructions in ["Installing the CRAN Package"](#installing-the-cran-package).
-
-#### Windows Preparation
-
-NOTE: Windows users may need to run with administrator rights (either R or the command prompt, depending on the way you are installing this package).
-
-Installing a 64-bit version of [Rtools](https://cran.r-project.org/bin/windows/Rtools/) is mandatory.
-
-After installing `Rtools` and `CMake`, be sure the following paths are added to the environment variable `PATH`. These may have been automatically added when installing other software.
-
-* `Rtools`
-    - If you have `Rtools` 3.x, example:
-        - `C:\Rtools\mingw_64\bin`
-    - If you have `Rtools` 4.0, example:
-        - `C:\rtools40\mingw64\bin`
-        - `C:\rtools40\usr\bin`
-* `CMake`
-    - example: `C:\Program Files\CMake\bin`
-* `R`
-    - example: `C:\Program Files\R\R-3.6.1\bin`
-
-NOTE: Two `Rtools` paths are required from `Rtools` 4.0 onwards because paths and the list of included software was changed in `Rtools` 4.0.
-
-#### Windows Toolchain Options
-
-A "toolchain" refers to the collection of software used to build the library. The R package can be built with three different toolchains.
-
-**Warning for Windows users**: it is recommended to use *Visual Studio* for its better multi-threading efficiency in Windows for many core systems. For very simple systems (dual core computers or worse), MinGW64 is recommended for maximum performance. If you do not know what to choose, it is recommended to use [Visual Studio](https://visualstudio.microsoft.com/downloads/), the default compiler. **Do not try using MinGW in Windows on many core systems. It may result in 10x slower results than Visual Studio.**
-
-**Visual Studio (default)**
-
-By default, the package will be built with [Visual Studio Build Tools](https://visualstudio.microsoft.com/downloads/).
-
-**MinGW (R 3.x)**
-
-If you are using R 3.x and installation fails with Visual Studio, `LightGBM` will fall back to using [MinGW](http://mingw-w64.org/doku.php) bundled with `Rtools`.
-
-If you want to force `LightGBM` to use MinGW (for any R version), pass `--use-mingw` to the installation script.
-
-```shell
-Rscript build_r.R --use-mingw
-```
-
-**MSYS2 (R 4.x)**
-
-If you are using R 4.x and installation fails with Visual Studio, `LightGBM` will fall back to using [MSYS2](https://www.msys2.org/). This should work with the tools already bundled in `Rtools` 4.0.
-
-If you want to force `LightGBM` to use MSYS2 (for any R version), pass `--use-msys2` to the installation script.
-
-```shell
-Rscript build_r.R --use-msys2
-```
-
-#### Mac OS Preparation
-
-You can perform installation either with **Apple Clang** or **gcc**. In case you prefer **Apple Clang**, you should install **OpenMP** (details for installation can be found in [Installation Guide](https://github.com/microsoft/LightGBM/blob/master/docs/Installation-Guide.rst#apple-clang)) first and **CMake** version 3.16 or higher is required. In case you prefer **gcc**, you need to install it (details for installation can be found in [Installation Guide](https://github.com/microsoft/LightGBM/blob/master/docs/Installation-Guide.rst#gcc)) and set some environment variables to tell R to use `gcc` and `g++`. If you install these from Homebrew, your versions of `g++` and `gcc` are most likely in `/usr/local/bin`, as shown below.
-
-```
-# replace 8 with version of gcc installed on your machine
-export CXX=/usr/local/bin/g++-8 CC=/usr/local/bin/gcc-8
-```
-
-#### Install with CMake
-
-After following the "preparation" steps above for your operating system, build and install the R-package with the following commands:
-
-```sh
-git clone --recursive https://github.com/microsoft/LightGBM
-cd LightGBM
-Rscript build_r.R
-```
-
-The `build_r.R` script builds the package in a temporary directory called `lightgbm_r`. It will destroy and recreate that directory each time you run the script. That script supports the following command-line options:
-
-- `--skip-install`: Build the package tarball, but do not install it.
-- `--use-gpu`: Build a GPU-enabled version of the library.
-- `--use-mingw`: Force the use of MinGW toolchain, regardless of R version.
-- `--use-msys2`: Force the use of MSYS2 toolchain, regardless of R version.
-
-Note: for the build with Visual Studio/VS Build Tools in Windows, you should use the Windows CMD or PowerShell.
-
-### Installing a GPU-enabled Build
-
-You will need to install Boost and OpenCL first: details for installation can be found in [Installation-Guide](https://github.com/microsoft/LightGBM/blob/master/docs/Installation-Guide.rst#build-gpu-version).
-
-After installing these other libraries, follow the steps in ["Installing from Source with CMake"](#install). When you reach the step that mentions `build_r.R`, pass the flag `--use-gpu`.
-
-```shell
-Rscript build_r.R --use-gpu
-```
-
-You may also need or want to provide additional configuration, depending on your setup. For example, you may need to provide locations for Boost and OpenCL.
-
-```shell
-Rscript build_r.R \
-    --use-gpu \
-    --opencl-library=/usr/lib/x86_64-linux-gnu/libOpenCL.so \
-    --boost-librarydir=/usr/lib/x86_64-linux-gnu
-```
-
-The following options correspond to the [CMake FindBoost options](https://cmake.org/cmake/help/latest/module/FindBoost.html) by the same names.
-
-* `--boost-root`
-* `--boost-dir`
-* `--boost-include-dir`
-* `--boost-librarydir`
-
-The following options correspond to the [CMake FindOpenCL options](https://cmake.org/cmake/help/latest/module/FindOpenCL.html) by the same names.
-
-* `--opencl-include-dir`
-* `--opencl-library`
-
-### Installing Precompiled Binaries
-
-Precompiled binaries for Mac and Windows are prepared by CRAN a few days after each release to CRAN. They can be installed with the following R code.
-
-```r
-install.packages(
-    "lightgbm"
-    , type = "both"
-    , repos = "https://cran.r-project.org"
-)
-```
-
-These packages do not require compilation, so they will be faster and easier to install than packages that are built from source.
-
-CRAN does not prepare precompiled binaries for Linux, and as of this writing neither does this project.
-
-### Installing from a Pre-compiled lib_lightgbm <a name="lib_lightgbm"></a>
-
-Previous versions of LightGBM offered the ability to first compile the C++ library (`lib_lightgbm.so` or `lib_lightgbm.dll`) and then build an R package that wraps it.
-
-As of version 3.0.0, this is no longer supported. If building from source is difficult for you, please [open an issue](https://github.com/microsoft/LightGBM/issues).
-
-Examples
---------
-
-Please visit [demo](https://github.com/microsoft/LightGBM/tree/master/R-package/demo):
-
-* [Basic walkthrough of wrappers](https://github.com/microsoft/LightGBM/blob/master/R-package/demo/basic_walkthrough.R)
-* [Boosting from existing prediction](https://github.com/microsoft/LightGBM/blob/master/R-package/demo/boost_from_prediction.R)
-* [Early Stopping](https://github.com/microsoft/LightGBM/blob/master/R-package/demo/early_stopping.R)
-* [Cross Validation](https://github.com/microsoft/LightGBM/blob/master/R-package/demo/cross_validation.R)
-* [Multiclass Training/Prediction](https://github.com/microsoft/LightGBM/blob/master/R-package/demo/multiclass.R)
-* [Leaf (in)Stability](https://github.com/microsoft/LightGBM/blob/master/R-package/demo/leaf_stability.R)
-* [Weight-Parameter Adjustment Relationship](https://github.com/microsoft/LightGBM/blob/master/R-package/demo/weight_param.R)
-
-Testing
--------
-
-The R package's unit tests are run automatically on every commit, via integrations like [GitHub Actions](https://github.com/microsoft/LightGBM/actions). Adding new tests in `R-package/tests/testthat` is a valuable way to improve the reliability of the R package.
-
-When adding tests, you may want to use test coverage to identify untested areas and to check if the tests you've added are covering all branches of the intended code.
-
-The example below shows how to generate code coverage for the R package on a macOS or Linux setup. To adjust for your environment, refer to [the customization step described above](#custom-installation-linux-mac).
-
-```shell
-# Install
-sh build-cran-package.sh
-
-# Get coverage
-Rscript -e " \
-    coverage  <- covr::package_coverage('./lightgbm_r', type = 'tests', quiet = FALSE);
-    print(coverage);
-    covr::report(coverage, file = file.path(getwd(), 'coverage.html'), browse = TRUE);
-    "
-```
-
-Preparing a CRAN Package
-------------------------
-
-This section is primarily for maintainers, but may help users and contributors to understand the structure of the R package.
-
-Most of `LightGBM` uses `CMake` to handle tasks like setting compiler and linker flags, including header file locations, and linking to other libraries. Because CRAN packages typically do not assume the presence of `CMake`, the R package uses an alternative method that is in the CRAN-supported toolchain for building R packages with C++ code: `Autoconf`.
-
-For more information on this approach, see ["Writing R Extensions"](https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Configure-and-cleanup).
-
-### Build a CRAN Package
-
-From the root of the repository, run the following.
-
-```shell
-git submodule update --init --recursive
-sh build-cran-package.sh
-```
-
-This will create a file `lightgbm_${VERSION}.tar.gz`, where `VERSION` is the version of `LightGBM`.
-
-Also, CRAN package is generated with every commit to any repo's branch and can be found in "Artifacts" section of the associated Azure Pipelines run.
-
-### Standard Installation from CRAN Package
-
-After building the package, install it with a command like the following:
-
-```shell
-R CMD install lightgbm_*.tar.gz
-```
-
-### Changing the CRAN Package
-
-A lot of details are handled automatically by `R CMD build` and `R CMD install`, so it can be difficult to understand how the files in the R package are related to each other. An extensive treatment of those details is available in ["Writing R Extensions"](https://cran.r-project.org/doc/manuals/r-release/R-exts.html).
-
-This section briefly explains the key files for building a CRAN package. To update the package, edit the files relevant to your change and re-run the steps in [Build a CRAN Package](#build-a-cran-package).
-
-**Linux or Mac**
-
-At build time, `configure` will be run and used to create a file `Makevars`, using `Makevars.in` as a template.
-
-1. Edit `configure.ac`.
-2. Create `configure` with `autoconf`. Do not edit it by hand. This file must be generated on Ubuntu 20.04.
-
-    If you have an Ubuntu 20.04 environment available, run the provided script from the root of the `LightGBM` repository.
-
-    ```shell
-    ./R-package/recreate-configure.sh
-    ```
-
-    If you do not have easy access to an Ubuntu 20.04 environment, the `configure` script can be generated using Docker by running the code below from the root of this repo.
-
-    ```shell
-    docker run \
-        -v $(pwd):/opt/LightGBM \
-        -w /opt/LightGBM \
-        -t ubuntu:20.04 \
-        ./R-package/recreate-configure.sh
-    ```
-
-    The version of `autoconf` used by this project is stored in `R-package/AUTOCONF_UBUNTU_VERSION`. To update that version, update that file and run the commands above. To see available versions, see https://packages.ubuntu.com/search?keywords=autoconf.
-
-3. Edit `src/Makevars.in`.
-
-Alternatively, GitHub Actions can re-generate this file for you. On a pull request (only on internal one, does not work for ones from forks), create a comment with this phrase:
-
-> /gha run r-configure
-
-**Configuring for Windows**
-
-At build time, `configure.win` will be run and used to create a file `Makevars.win`, using `Makevars.win.in` as a template.
-
-1. Edit `configure.win` directly.
-2. Edit `src/Makevars.win.in`.
-
-### Testing the CRAN Package
-
-`{lightgbm}` is tested automatically on every commit, across many combinations of operating system, R version, and compiler. This section describes how to test the package locally while you are developing.
-
-#### Windows, Mac, and Linux
-
-```shell
-sh build-cran-package.sh
-R CMD check --as-cran lightgbm_*.tar.gz
-```
-
-#### Solaris
-
-All packages uploaded to CRAN must pass `R CMD check` on Solaris 10. To test LightGBM on this operating system, you can use the free service [R Hub](https://builder.r-hub.io/), a free service generously provided by the R Consortium.
-
-```shell
-sh build-cran-package.sh
-```
-
-```r
-package_tarball <- paste0("lightgbm_", readLines("VERSION.txt")[1], ".tar.gz")
-rhub::check(
-    path = package_tarball
-    , email = "your_email_here"
-    , check_args = "--as-cran"
-    , platform = c(
-        "solaris-x86-patched"
-        , "solaris-x86-patched-ods"
-    )
-    , env_vars = c(
-        "R_COMPILE_AND_INSTALL_PACKAGES" = "always"
-    )
-)
-```
-
-Alternatively, GitHub Actions can run code above for you. On a pull request, create a comment with this phrase:
-
-> /gha run r-solaris
-
-**NOTE:** Please do this only once you see that other R tests on a pull request are passing. R Hub is a free resource with limited capacity, and we want to be respectful community members.
-
-#### UBSAN
-
-All packages uploaded to CRAN must pass a build using `gcc` instrumented with two sanitizers: the Address Sanitizer (ASAN) and the Undefined Behavior Sanitizer (UBSAN). For more background, see [this blog post](http://dirk.eddelbuettel.com/code/sanitizers.html).
-
-You can replicate these checks locally using Docker.
-
-```shell
-docker run \
-    -v $(pwd):/opt/LightGBM \
-    -w /opt/LightGBM \
-    -it rhub/rocker-gcc-san \
-    /bin/bash
-
-Rscript -e "install.packages(c('R6', 'data.table', 'jsonlite', 'testthat'), repos = 'https://cran.rstudio.com', Ncpus = parallel::detectCores())"
-
-sh build-cran-package.sh
-
-Rdevel CMD install lightgbm_*.tar.gz
-cd R-package/tests
-Rscriptdevel testthat.R
-```
-
-#### Valgrind
-
-All packages uploaded to CRAN must be built and tested without raising any issues from `valgrind`. `valgrind` is a profiler that can catch serious issues like memory leaks and illegal writes. For more information, see [this blog post](https://reside-ic.github.io/blog/debugging-and-fixing-crans-additional-checks-errors/).
-
-You can replicate these checks locally using Docker. Note that instrumented versions of R built to use `valgrind` run much slower, and these tests may take as long as 20 minutes to run.
-
-```shell
-docker run \
-    -v $(pwd):/opt/LightGBM \
-    -w /opt/LightGBM \
-    -it \
-        wch1/r-debug
-
-RDscriptvalgrind -e "install.packages(c('R6', 'data.table', 'jsonlite', 'testthat'), repos = 'https://cran.rstudio.com', Ncpus = parallel::detectCores())"
-
-sh build-cran-package.sh
-
-RDvalgrind CMD INSTALL \
-    --preclean \
-    --install-tests \
-        lightgbm_*.tar.gz
-
-cd R-package/tests
-
-RDvalgrind \
-    --no-readline \
-    --vanilla \
-    -d "valgrind --tool=memcheck --leak-check=full --track-origins=yes" \
-        -f testthat.R \
-2>&1 \
-| tee out.log \
-| cat
-```
-
-These tests can also be triggered on any pull request by leaving a comment in a pull request:
-
-> /gha run r-valgrind
-
-External (Unofficial) Repositories
-----------------------------------
-
-Projects listed here are not maintained or endorsed by the `LightGBM` development team, but may offer some features currently missing from the main R package.
-
-* [lightgbm.py](https://github.com/kapsner/lightgbm.py): This R package offers a wrapper built with `reticulate`, a package used to call Python code from R. If you are comfortable with the added installation complexity of installing `lightgbm`'s Python package and the performance cost of passing data between R and Python, you might find that this package offers some features that are not yet available in the native `lightgbm` R package.
-
-Known Issues
-------------
-
-For information about known issues with the R package, see the [R-package section of LightGBM's main FAQ page](https://lightgbm.readthedocs.io/en/latest/FAQ.html#r-package).
diff --git a/R-package/cleanup b/R-package/cleanup
deleted file mode 100755
index 3c020d388..000000000
--- a/R-package/cleanup
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-rm -f src/Makevars
diff --git a/R-package/configure b/R-package/configure
deleted file mode 100755
index a7b131fc4..000000000
--- a/R-package/configure
+++ /dev/null
@@ -1,3010 +0,0 @@
-#! /bin/sh
-# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for lightgbm 3.2.1.99.
-#
-#
-# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
-#
-#
-# This configure script is free software; the Free Software Foundation
-# gives unlimited permission to copy, distribute and modify it.
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in #(
-  *posix*) :
-    set -o posix ;; #(
-  *) :
-     ;;
-esac
-fi
-
-
-as_nl='
-'
-export as_nl
-# Printing a long string crashes Solaris 7 /usr/bin/printf.
-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-# Prefer a ksh shell builtin over an external printf program on Solaris,
-# but without wasting forks for bash or zsh.
-if test -z "$BASH_VERSION$ZSH_VERSION" \
-    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
-  as_echo='print -r --'
-  as_echo_n='print -rn --'
-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
-  as_echo='printf %s\n'
-  as_echo_n='printf %s'
-else
-  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
-    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
-    as_echo_n='/usr/ucb/echo -n'
-  else
-    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
-    as_echo_n_body='eval
-      arg=$1;
-      case $arg in #(
-      *"$as_nl"*)
-	expr "X$arg" : "X\\(.*\\)$as_nl";
-	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
-      esac;
-      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
-    '
-    export as_echo_n_body
-    as_echo_n='sh -c $as_echo_n_body as_echo'
-  fi
-  export as_echo_body
-  as_echo='sh -c $as_echo_body as_echo'
-fi
-
-# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
-  PATH_SEPARATOR=:
-  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
-    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
-      PATH_SEPARATOR=';'
-  }
-fi
-
-
-# IFS
-# We need space, tab and new line, in precisely that order.  Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-IFS=" ""	$as_nl"
-
-# Find who we are.  Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
-  *[\\/]* ) as_myself=$0 ;;
-  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-  done
-IFS=$as_save_IFS
-
-     ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
-  as_myself=$0
-fi
-if test ! -f "$as_myself"; then
-  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
-  exit 1
-fi
-
-# Unset variables that we do not need and which cause bugs (e.g. in
-# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
-# suppresses any "Segmentation fault" message there.  '((' could
-# trigger a bug in pdksh 5.2.14.
-for as_var in BASH_ENV ENV MAIL MAILPATH
-do eval test x\${$as_var+set} = xset \
-  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-# Use a proper internal environment variable to ensure we don't fall
-  # into an infinite loop, continuously re-executing ourselves.
-  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
-    _as_can_reexec=no; export _as_can_reexec;
-    # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
-  *v*x* | *x*v* ) as_opts=-vx ;;
-  *v* ) as_opts=-v ;;
-  *x* ) as_opts=-x ;;
-  * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-as_fn_exit 255
-  fi
-  # We don't want this to propagate to other subprocesses.
-          { _as_can_reexec=; unset _as_can_reexec;}
-if test "x$CONFIG_SHELL" = x; then
-  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '\${1+\"\$@\"}'='\"\$@\"'
-  setopt NO_GLOB_SUBST
-else
-  case \`(set -o) 2>/dev/null\` in #(
-  *posix*) :
-    set -o posix ;; #(
-  *) :
-     ;;
-esac
-fi
-"
-  as_required="as_fn_return () { (exit \$1); }
-as_fn_success () { as_fn_return 0; }
-as_fn_failure () { as_fn_return 1; }
-as_fn_ret_success () { return 0; }
-as_fn_ret_failure () { return 1; }
-
-exitcode=0
-as_fn_success || { exitcode=1; echo as_fn_success failed.; }
-as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
-as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
-as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
-if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
-
-else
-  exitcode=1; echo positional parameters were not saved.
-fi
-test x\$exitcode = x0 || exit 1
-test -x / || exit 1"
-  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
-  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
-  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
-  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
-  if (eval "$as_required") 2>/dev/null; then :
-  as_have_required=yes
-else
-  as_have_required=no
-fi
-  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
-
-else
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-as_found=false
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  as_found=:
-  case $as_dir in #(
-	 /*)
-	   for as_base in sh bash ksh sh5; do
-	     # Try only shells that exist, to save several forks.
-	     as_shell=$as_dir/$as_base
-	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
-		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
-  CONFIG_SHELL=$as_shell as_have_required=yes
-		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
-  break 2
-fi
-fi
-	   done;;
-       esac
-  as_found=false
-done
-$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
-	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
-  CONFIG_SHELL=$SHELL as_have_required=yes
-fi; }
-IFS=$as_save_IFS
-
-
-      if test "x$CONFIG_SHELL" != x; then :
-  export CONFIG_SHELL
-             # We cannot yet assume a decent shell, so we have to provide a
-# neutralization value for shells without unset; and this also
-# works around shells that cannot unset nonexistent variables.
-# Preserve -v and -x to the replacement shell.
-BASH_ENV=/dev/null
-ENV=/dev/null
-(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
-case $- in # ((((
-  *v*x* | *x*v* ) as_opts=-vx ;;
-  *v* ) as_opts=-v ;;
-  *x* ) as_opts=-x ;;
-  * ) as_opts= ;;
-esac
-exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
-# Admittedly, this is quite paranoid, since all the known shells bail
-# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-exit 255
-fi
-
-    if test x$as_have_required = xno; then :
-  $as_echo "$0: This script requires a shell more modern than all"
-  $as_echo "$0: the shells that I found on your system."
-  if test x${ZSH_VERSION+set} = xset ; then
-    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
-    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
-  else
-    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
-$0: including any error possibly output before this
-$0: message. Then install a modern shell, or manually run
-$0: the script under such a shell if you do have one."
-  fi
-  exit 1
-fi
-fi
-fi
-SHELL=${CONFIG_SHELL-/bin/sh}
-export SHELL
-# Unset more variables known to interfere with behavior of common tools.
-CLICOLOR_FORCE= GREP_OPTIONS=
-unset CLICOLOR_FORCE GREP_OPTIONS
-
-## --------------------- ##
-## M4sh Shell Functions. ##
-## --------------------- ##
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
-  { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
-  return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
-  set +e
-  as_fn_set_status $1
-  exit $1
-} # as_fn_exit
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
-  case $as_dir in #(
-  -*) as_dir=./$as_dir;;
-  esac
-  test -d "$as_dir" || eval $as_mkdir_p || {
-    as_dirs=
-    while :; do
-      case $as_dir in #(
-      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
-      *) as_qdir=$as_dir;;
-      esac
-      as_dirs="'$as_qdir' $as_dirs"
-      as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-	 X"$as_dir" : 'X\(//\)[^/]' \| \
-	 X"$as_dir" : 'X\(//\)$' \| \
-	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-	    s//\1/
-	    q
-	  }
-	  /^X\(\/\/\)[^/].*/{
-	    s//\1/
-	    q
-	  }
-	  /^X\(\/\/\)$/{
-	    s//\1/
-	    q
-	  }
-	  /^X\(\/\).*/{
-	    s//\1/
-	    q
-	  }
-	  s/.*/./; q'`
-      test -d "$as_dir" && break
-    done
-    test -z "$as_dirs" || eval "mkdir $as_dirs"
-  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
-  test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
-  eval 'as_fn_append ()
-  {
-    eval $1+=\$2
-  }'
-else
-  as_fn_append ()
-  {
-    eval $1=\$$1\$2
-  }
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
-  eval 'as_fn_arith ()
-  {
-    as_val=$(( $* ))
-  }'
-else
-  as_fn_arith ()
-  {
-    as_val=`expr "$@" || test $? -eq 1`
-  }
-fi # as_fn_arith
-
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
-  as_status=$1; test $as_status -eq 0 && as_status=1
-  if test "$4"; then
-    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
-  fi
-  $as_echo "$as_me: error: $2" >&2
-  as_fn_exit $as_status
-} # as_fn_error
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
-   test "X`expr 00001 : '.*\(...\)'`" = X001; then
-  as_expr=expr
-else
-  as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
-  as_basename=basename
-else
-  as_basename=false
-fi
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
-  as_dirname=dirname
-else
-  as_dirname=false
-fi
-
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
-	 X"$0" : 'X\(//\)$' \| \
-	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$0" |
-    sed '/^.*\/\([^/][^/]*\)\/*$/{
-	    s//\1/
-	    q
-	  }
-	  /^X\/\(\/\/\)$/{
-	    s//\1/
-	    q
-	  }
-	  /^X\/\(\/\).*/{
-	    s//\1/
-	    q
-	  }
-	  s/.*/./; q'`
-
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-
-  as_lineno_1=$LINENO as_lineno_1a=$LINENO
-  as_lineno_2=$LINENO as_lineno_2a=$LINENO
-  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
-  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
-  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
-  sed -n '
-    p
-    /[$]LINENO/=
-  ' <$as_myself |
-    sed '
-      s/[$]LINENO.*/&-/
-      t lineno
-      b
-      :lineno
-      N
-      :loop
-      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
-      t loop
-      s/-\n.*//
-    ' >$as_me.lineno &&
-  chmod +x "$as_me.lineno" ||
-    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
-
-  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
-  # already done that, so ensure we don't try to do so again and fall
-  # in an infinite loop.  This has already happened in practice.
-  _as_can_reexec=no; export _as_can_reexec
-  # Don't try to exec as it changes $[0], causing all sort of problems
-  # (the dirname of $[0] is not the place where we might find the
-  # original and so on.  Autoconf is especially sensitive to this).
-  . "./$as_me.lineno"
-  # Exit status is that of the last command.
-  exit
-}
-
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
-  case `echo 'xy\c'` in
-  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
-  xy)  ECHO_C='\c';;
-  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
-       ECHO_T='	';;
-  esac;;
-*)
-  ECHO_N='-n';;
-esac
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
-  rm -f conf$$.dir/conf$$.file
-else
-  rm -f conf$$.dir
-  mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
-  if ln -s conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s='ln -s'
-    # ... but there are two gotchas:
-    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
-    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -pR'.
-    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -pR'
-  elif ln conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s=ln
-  else
-    as_ln_s='cp -pR'
-  fi
-else
-  as_ln_s='cp -pR'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-if mkdir -p . 2>/dev/null; then
-  as_mkdir_p='mkdir -p "$as_dir"'
-else
-  test -d ./-p && rmdir ./-p
-  as_mkdir_p=false
-fi
-
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-
-test -n "$DJDIR" || exec 7<&0 </dev/null
-exec 6>&1
-
-# Name of the host.
-# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
-# so uname gets run too.
-ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
-
-#
-# Initializations.
-#
-ac_default_prefix=/usr/local
-ac_clean_files=
-ac_config_libobj_dir=.
-LIBOBJS=
-cross_compiling=no
-subdirs=
-MFLAGS=
-MAKEFLAGS=
-
-# Identity of this package.
-PACKAGE_NAME='lightgbm'
-PACKAGE_TARNAME='lightgbm'
-PACKAGE_VERSION='3.2.1.99'
-PACKAGE_STRING='lightgbm 3.2.1.99'
-PACKAGE_BUGREPORT=''
-PACKAGE_URL=''
-
-ac_subst_vars='LTLIBOBJS
-LIBOBJS
-LGB_CPPFLAGS
-OPENMP_LIB
-OPENMP_CXXFLAGS
-target_alias
-host_alias
-build_alias
-LIBS
-ECHO_T
-ECHO_N
-ECHO_C
-DEFS
-mandir
-localedir
-libdir
-psdir
-pdfdir
-dvidir
-htmldir
-infodir
-docdir
-oldincludedir
-includedir
-runstatedir
-localstatedir
-sharedstatedir
-sysconfdir
-datadir
-datarootdir
-libexecdir
-sbindir
-bindir
-program_transform_name
-prefix
-exec_prefix
-PACKAGE_URL
-PACKAGE_BUGREPORT
-PACKAGE_STRING
-PACKAGE_VERSION
-PACKAGE_TARNAME
-PACKAGE_NAME
-PATH_SEPARATOR
-SHELL'
-ac_subst_files=''
-ac_user_opts='
-enable_option_checking
-'
-      ac_precious_vars='build_alias
-host_alias
-target_alias'
-
-
-# Initialize some variables set by options.
-ac_init_help=
-ac_init_version=false
-ac_unrecognized_opts=
-ac_unrecognized_sep=
-# The variables have the same names as the options, with
-# dashes changed to underlines.
-cache_file=/dev/null
-exec_prefix=NONE
-no_create=
-no_recursion=
-prefix=NONE
-program_prefix=NONE
-program_suffix=NONE
-program_transform_name=s,x,x,
-silent=
-site=
-srcdir=
-verbose=
-x_includes=NONE
-x_libraries=NONE
-
-# Installation directory options.
-# These are left unexpanded so users can "make install exec_prefix=/foo"
-# and all the variables that are supposed to be based on exec_prefix
-# by default will actually change.
-# Use braces instead of parens because sh, perl, etc. also accept them.
-# (The list follows the same order as the GNU Coding Standards.)
-bindir='${exec_prefix}/bin'
-sbindir='${exec_prefix}/sbin'
-libexecdir='${exec_prefix}/libexec'
-datarootdir='${prefix}/share'
-datadir='${datarootdir}'
-sysconfdir='${prefix}/etc'
-sharedstatedir='${prefix}/com'
-localstatedir='${prefix}/var'
-runstatedir='${localstatedir}/run'
-includedir='${prefix}/include'
-oldincludedir='/usr/include'
-docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
-infodir='${datarootdir}/info'
-htmldir='${docdir}'
-dvidir='${docdir}'
-pdfdir='${docdir}'
-psdir='${docdir}'
-libdir='${exec_prefix}/lib'
-localedir='${datarootdir}/locale'
-mandir='${datarootdir}/man'
-
-ac_prev=
-ac_dashdash=
-for ac_option
-do
-  # If the previous option needs an argument, assign it.
-  if test -n "$ac_prev"; then
-    eval $ac_prev=\$ac_option
-    ac_prev=
-    continue
-  fi
-
-  case $ac_option in
-  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
-  *=)   ac_optarg= ;;
-  *)    ac_optarg=yes ;;
-  esac
-
-  # Accept the important Cygnus configure options, so we can diagnose typos.
-
-  case $ac_dashdash$ac_option in
-  --)
-    ac_dashdash=yes ;;
-
-  -bindir | --bindir | --bindi | --bind | --bin | --bi)
-    ac_prev=bindir ;;
-  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
-    bindir=$ac_optarg ;;
-
-  -build | --build | --buil | --bui | --bu)
-    ac_prev=build_alias ;;
-  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
-    build_alias=$ac_optarg ;;
-
-  -cache-file | --cache-file | --cache-fil | --cache-fi \
-  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
-    ac_prev=cache_file ;;
-  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
-  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
-    cache_file=$ac_optarg ;;
-
-  --config-cache | -C)
-    cache_file=config.cache ;;
-
-  -datadir | --datadir | --datadi | --datad)
-    ac_prev=datadir ;;
-  -datadir=* | --datadir=* | --datadi=* | --datad=*)
-    datadir=$ac_optarg ;;
-
-  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
-  | --dataroo | --dataro | --datar)
-    ac_prev=datarootdir ;;
-  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
-  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
-    datarootdir=$ac_optarg ;;
-
-  -disable-* | --disable-*)
-    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
-    # Reject names that are not valid shell variable names.
-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid feature name: $ac_useropt"
-    ac_useropt_orig=$ac_useropt
-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
-    case $ac_user_opts in
-      *"
-"enable_$ac_useropt"
-"*) ;;
-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
-	 ac_unrecognized_sep=', ';;
-    esac
-    eval enable_$ac_useropt=no ;;
-
-  -docdir | --docdir | --docdi | --doc | --do)
-    ac_prev=docdir ;;
-  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
-    docdir=$ac_optarg ;;
-
-  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
-    ac_prev=dvidir ;;
-  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
-    dvidir=$ac_optarg ;;
-
-  -enable-* | --enable-*)
-    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
-    # Reject names that are not valid shell variable names.
-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid feature name: $ac_useropt"
-    ac_useropt_orig=$ac_useropt
-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
-    case $ac_user_opts in
-      *"
-"enable_$ac_useropt"
-"*) ;;
-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
-	 ac_unrecognized_sep=', ';;
-    esac
-    eval enable_$ac_useropt=\$ac_optarg ;;
-
-  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
-  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
-  | --exec | --exe | --ex)
-    ac_prev=exec_prefix ;;
-  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
-  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
-  | --exec=* | --exe=* | --ex=*)
-    exec_prefix=$ac_optarg ;;
-
-  -gas | --gas | --ga | --g)
-    # Obsolete; use --with-gas.
-    with_gas=yes ;;
-
-  -help | --help | --hel | --he | -h)
-    ac_init_help=long ;;
-  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
-    ac_init_help=recursive ;;
-  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
-    ac_init_help=short ;;
-
-  -host | --host | --hos | --ho)
-    ac_prev=host_alias ;;
-  -host=* | --host=* | --hos=* | --ho=*)
-    host_alias=$ac_optarg ;;
-
-  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
-    ac_prev=htmldir ;;
-  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
-  | --ht=*)
-    htmldir=$ac_optarg ;;
-
-  -includedir | --includedir | --includedi | --included | --include \
-  | --includ | --inclu | --incl | --inc)
-    ac_prev=includedir ;;
-  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
-  | --includ=* | --inclu=* | --incl=* | --inc=*)
-    includedir=$ac_optarg ;;
-
-  -infodir | --infodir | --infodi | --infod | --info | --inf)
-    ac_prev=infodir ;;
-  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
-    infodir=$ac_optarg ;;
-
-  -libdir | --libdir | --libdi | --libd)
-    ac_prev=libdir ;;
-  -libdir=* | --libdir=* | --libdi=* | --libd=*)
-    libdir=$ac_optarg ;;
-
-  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
-  | --libexe | --libex | --libe)
-    ac_prev=libexecdir ;;
-  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
-  | --libexe=* | --libex=* | --libe=*)
-    libexecdir=$ac_optarg ;;
-
-  -localedir | --localedir | --localedi | --localed | --locale)
-    ac_prev=localedir ;;
-  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
-    localedir=$ac_optarg ;;
-
-  -localstatedir | --localstatedir | --localstatedi | --localstated \
-  | --localstate | --localstat | --localsta | --localst | --locals)
-    ac_prev=localstatedir ;;
-  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
-  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
-    localstatedir=$ac_optarg ;;
-
-  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
-    ac_prev=mandir ;;
-  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
-    mandir=$ac_optarg ;;
-
-  -nfp | --nfp | --nf)
-    # Obsolete; use --without-fp.
-    with_fp=no ;;
-
-  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
-  | --no-cr | --no-c | -n)
-    no_create=yes ;;
-
-  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
-  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
-    no_recursion=yes ;;
-
-  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
-  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
-  | --oldin | --oldi | --old | --ol | --o)
-    ac_prev=oldincludedir ;;
-  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
-  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
-  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
-    oldincludedir=$ac_optarg ;;
-
-  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
-    ac_prev=prefix ;;
-  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
-    prefix=$ac_optarg ;;
-
-  -program-prefix | --program-prefix | --program-prefi | --program-pref \
-  | --program-pre | --program-pr | --program-p)
-    ac_prev=program_prefix ;;
-  -program-prefix=* | --program-prefix=* | --program-prefi=* \
-  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
-    program_prefix=$ac_optarg ;;
-
-  -program-suffix | --program-suffix | --program-suffi | --program-suff \
-  | --program-suf | --program-su | --program-s)
-    ac_prev=program_suffix ;;
-  -program-suffix=* | --program-suffix=* | --program-suffi=* \
-  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
-    program_suffix=$ac_optarg ;;
-
-  -program-transform-name | --program-transform-name \
-  | --program-transform-nam | --program-transform-na \
-  | --program-transform-n | --program-transform- \
-  | --program-transform | --program-transfor \
-  | --program-transfo | --program-transf \
-  | --program-trans | --program-tran \
-  | --progr-tra | --program-tr | --program-t)
-    ac_prev=program_transform_name ;;
-  -program-transform-name=* | --program-transform-name=* \
-  | --program-transform-nam=* | --program-transform-na=* \
-  | --program-transform-n=* | --program-transform-=* \
-  | --program-transform=* | --program-transfor=* \
-  | --program-transfo=* | --program-transf=* \
-  | --program-trans=* | --program-tran=* \
-  | --progr-tra=* | --program-tr=* | --program-t=*)
-    program_transform_name=$ac_optarg ;;
-
-  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
-    ac_prev=pdfdir ;;
-  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
-    pdfdir=$ac_optarg ;;
-
-  -psdir | --psdir | --psdi | --psd | --ps)
-    ac_prev=psdir ;;
-  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
-    psdir=$ac_optarg ;;
-
-  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
-  | -silent | --silent | --silen | --sile | --sil)
-    silent=yes ;;
-
-  -runstatedir | --runstatedir | --runstatedi | --runstated \
-  | --runstate | --runstat | --runsta | --runst | --runs \
-  | --run | --ru | --r)
-    ac_prev=runstatedir ;;
-  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
-  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
-  | --run=* | --ru=* | --r=*)
-    runstatedir=$ac_optarg ;;
-
-  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
-    ac_prev=sbindir ;;
-  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
-  | --sbi=* | --sb=*)
-    sbindir=$ac_optarg ;;
-
-  -sharedstatedir | --sharedstatedir | --sharedstatedi \
-  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
-  | --sharedst | --shareds | --shared | --share | --shar \
-  | --sha | --sh)
-    ac_prev=sharedstatedir ;;
-  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
-  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
-  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
-  | --sha=* | --sh=*)
-    sharedstatedir=$ac_optarg ;;
-
-  -site | --site | --sit)
-    ac_prev=site ;;
-  -site=* | --site=* | --sit=*)
-    site=$ac_optarg ;;
-
-  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
-    ac_prev=srcdir ;;
-  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
-    srcdir=$ac_optarg ;;
-
-  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
-  | --syscon | --sysco | --sysc | --sys | --sy)
-    ac_prev=sysconfdir ;;
-  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
-  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
-    sysconfdir=$ac_optarg ;;
-
-  -target | --target | --targe | --targ | --tar | --ta | --t)
-    ac_prev=target_alias ;;
-  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
-    target_alias=$ac_optarg ;;
-
-  -v | -verbose | --verbose | --verbos | --verbo | --verb)
-    verbose=yes ;;
-
-  -version | --version | --versio | --versi | --vers | -V)
-    ac_init_version=: ;;
-
-  -with-* | --with-*)
-    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
-    # Reject names that are not valid shell variable names.
-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid package name: $ac_useropt"
-    ac_useropt_orig=$ac_useropt
-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
-    case $ac_user_opts in
-      *"
-"with_$ac_useropt"
-"*) ;;
-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
-	 ac_unrecognized_sep=', ';;
-    esac
-    eval with_$ac_useropt=\$ac_optarg ;;
-
-  -without-* | --without-*)
-    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
-    # Reject names that are not valid shell variable names.
-    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
-      as_fn_error $? "invalid package name: $ac_useropt"
-    ac_useropt_orig=$ac_useropt
-    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
-    case $ac_user_opts in
-      *"
-"with_$ac_useropt"
-"*) ;;
-      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
-	 ac_unrecognized_sep=', ';;
-    esac
-    eval with_$ac_useropt=no ;;
-
-  --x)
-    # Obsolete; use --with-x.
-    with_x=yes ;;
-
-  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
-  | --x-incl | --x-inc | --x-in | --x-i)
-    ac_prev=x_includes ;;
-  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
-  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
-    x_includes=$ac_optarg ;;
-
-  -x-libraries | --x-libraries | --x-librarie | --x-librari \
-  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
-    ac_prev=x_libraries ;;
-  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
-  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
-    x_libraries=$ac_optarg ;;
-
-  -*) as_fn_error $? "unrecognized option: \`$ac_option'
-Try \`$0 --help' for more information"
-    ;;
-
-  *=*)
-    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
-    # Reject names that are not valid shell variable names.
-    case $ac_envvar in #(
-      '' | [0-9]* | *[!_$as_cr_alnum]* )
-      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
-    esac
-    eval $ac_envvar=\$ac_optarg
-    export $ac_envvar ;;
-
-  *)
-    # FIXME: should be removed in autoconf 3.0.
-    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
-    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
-      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
-    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
-    ;;
-
-  esac
-done
-
-if test -n "$ac_prev"; then
-  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
-  as_fn_error $? "missing argument to $ac_option"
-fi
-
-if test -n "$ac_unrecognized_opts"; then
-  case $enable_option_checking in
-    no) ;;
-    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
-    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
-  esac
-fi
-
-# Check all directory arguments for consistency.
-for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
-		datadir sysconfdir sharedstatedir localstatedir includedir \
-		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir runstatedir
-do
-  eval ac_val=\$$ac_var
-  # Remove trailing slashes.
-  case $ac_val in
-    */ )
-      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
-      eval $ac_var=\$ac_val;;
-  esac
-  # Be sure to have absolute directory names.
-  case $ac_val in
-    [\\/$]* | ?:[\\/]* )  continue;;
-    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
-  esac
-  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
-done
-
-# There might be people who depend on the old broken behavior: `$host'
-# used to hold the argument of --host etc.
-# FIXME: To remove some day.
-build=$build_alias
-host=$host_alias
-target=$target_alias
-
-# FIXME: To remove some day.
-if test "x$host_alias" != x; then
-  if test "x$build_alias" = x; then
-    cross_compiling=maybe
-  elif test "x$build_alias" != "x$host_alias"; then
-    cross_compiling=yes
-  fi
-fi
-
-ac_tool_prefix=
-test -n "$host_alias" && ac_tool_prefix=$host_alias-
-
-test "$silent" = yes && exec 6>/dev/null
-
-
-ac_pwd=`pwd` && test -n "$ac_pwd" &&
-ac_ls_di=`ls -di .` &&
-ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
-  as_fn_error $? "working directory cannot be determined"
-test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
-  as_fn_error $? "pwd does not report name of working directory"
-
-
-# Find the source files, if location was not specified.
-if test -z "$srcdir"; then
-  ac_srcdir_defaulted=yes
-  # Try the directory containing this script, then the parent directory.
-  ac_confdir=`$as_dirname -- "$as_myself" ||
-$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-	 X"$as_myself" : 'X\(//\)[^/]' \| \
-	 X"$as_myself" : 'X\(//\)$' \| \
-	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_myself" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-	    s//\1/
-	    q
-	  }
-	  /^X\(\/\/\)[^/].*/{
-	    s//\1/
-	    q
-	  }
-	  /^X\(\/\/\)$/{
-	    s//\1/
-	    q
-	  }
-	  /^X\(\/\).*/{
-	    s//\1/
-	    q
-	  }
-	  s/.*/./; q'`
-  srcdir=$ac_confdir
-  if test ! -r "$srcdir/$ac_unique_file"; then
-    srcdir=..
-  fi
-else
-  ac_srcdir_defaulted=no
-fi
-if test ! -r "$srcdir/$ac_unique_file"; then
-  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
-  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
-fi
-ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
-ac_abs_confdir=`(
-	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
-	pwd)`
-# When building in place, set srcdir=.
-if test "$ac_abs_confdir" = "$ac_pwd"; then
-  srcdir=.
-fi
-# Remove unnecessary trailing slashes from srcdir.
-# Double slashes in file names in object file debugging info
-# mess up M-x gdb in Emacs.
-case $srcdir in
-*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
-esac
-for ac_var in $ac_precious_vars; do
-  eval ac_env_${ac_var}_set=\${${ac_var}+set}
-  eval ac_env_${ac_var}_value=\$${ac_var}
-  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
-  eval ac_cv_env_${ac_var}_value=\$${ac_var}
-done
-
-#
-# Report the --help message.
-#
-if test "$ac_init_help" = "long"; then
-  # Omit some internal or obsolete options to make the list less imposing.
-  # This message is too long to be a string in the A/UX 3.1 sh.
-  cat <<_ACEOF
-\`configure' configures lightgbm 3.2.1.99 to adapt to many kinds of systems.
-
-Usage: $0 [OPTION]... [VAR=VALUE]...
-
-To assign environment variables (e.g., CC, CFLAGS...), specify them as
-VAR=VALUE.  See below for descriptions of some of the useful variables.
-
-Defaults for the options are specified in brackets.
-
-Configuration:
-  -h, --help              display this help and exit
-      --help=short        display options specific to this package
-      --help=recursive    display the short help of all the included packages
-  -V, --version           display version information and exit
-  -q, --quiet, --silent   do not print \`checking ...' messages
-      --cache-file=FILE   cache test results in FILE [disabled]
-  -C, --config-cache      alias for \`--cache-file=config.cache'
-  -n, --no-create         do not create output files
-      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
-
-Installation directories:
-  --prefix=PREFIX         install architecture-independent files in PREFIX
-                          [$ac_default_prefix]
-  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
-                          [PREFIX]
-
-By default, \`make install' will install all the files in
-\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
-an installation prefix other than \`$ac_default_prefix' using \`--prefix',
-for instance \`--prefix=\$HOME'.
-
-For better control, use the options below.
-
-Fine tuning of the installation directories:
-  --bindir=DIR            user executables [EPREFIX/bin]
-  --sbindir=DIR           system admin executables [EPREFIX/sbin]
-  --libexecdir=DIR        program executables [EPREFIX/libexec]
-  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
-  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
-  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
-  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
-  --libdir=DIR            object code libraries [EPREFIX/lib]
-  --includedir=DIR        C header files [PREFIX/include]
-  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
-  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
-  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
-  --infodir=DIR           info documentation [DATAROOTDIR/info]
-  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
-  --mandir=DIR            man documentation [DATAROOTDIR/man]
-  --docdir=DIR            documentation root [DATAROOTDIR/doc/lightgbm]
-  --htmldir=DIR           html documentation [DOCDIR]
-  --dvidir=DIR            dvi documentation [DOCDIR]
-  --pdfdir=DIR            pdf documentation [DOCDIR]
-  --psdir=DIR             ps documentation [DOCDIR]
-_ACEOF
-
-  cat <<\_ACEOF
-_ACEOF
-fi
-
-if test -n "$ac_init_help"; then
-  case $ac_init_help in
-     short | recursive ) echo "Configuration of lightgbm 3.2.1.99:";;
-   esac
-  cat <<\_ACEOF
-
-Report bugs to the package provider.
-_ACEOF
-ac_status=$?
-fi
-
-if test "$ac_init_help" = "recursive"; then
-  # If there are subdirs, report their specific --help.
-  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
-    test -d "$ac_dir" ||
-      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
-      continue
-    ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
-  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
-  # A ".." for each directory in $ac_dir_suffix.
-  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
-  case $ac_top_builddir_sub in
-  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
-  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
-  esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
-  .)  # We are building in place.
-    ac_srcdir=.
-    ac_top_srcdir=$ac_top_builddir_sub
-    ac_abs_top_srcdir=$ac_pwd ;;
-  [\\/]* | ?:[\\/]* )  # Absolute name.
-    ac_srcdir=$srcdir$ac_dir_suffix;
-    ac_top_srcdir=$srcdir
-    ac_abs_top_srcdir=$srcdir ;;
-  *) # Relative name.
-    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
-    ac_top_srcdir=$ac_top_build_prefix$srcdir
-    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
-    cd "$ac_dir" || { ac_status=$?; continue; }
-    # Check for guested configure.
-    if test -f "$ac_srcdir/configure.gnu"; then
-      echo &&
-      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
-    elif test -f "$ac_srcdir/configure"; then
-      echo &&
-      $SHELL "$ac_srcdir/configure" --help=recursive
-    else
-      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
-    fi || ac_status=$?
-    cd "$ac_pwd" || { ac_status=$?; break; }
-  done
-fi
-
-test -n "$ac_init_help" && exit $ac_status
-if $ac_init_version; then
-  cat <<\_ACEOF
-lightgbm configure 3.2.1.99
-generated by GNU Autoconf 2.69
-
-Copyright (C) 2012 Free Software Foundation, Inc.
-This configure script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it.
-_ACEOF
-  exit
-fi
-
-## ------------------------ ##
-## Autoconf initialization. ##
-## ------------------------ ##
-cat >config.log <<_ACEOF
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
-
-It was created by lightgbm $as_me 3.2.1.99, which was
-generated by GNU Autoconf 2.69.  Invocation command line was
-
-  $ $0 $@
-
-_ACEOF
-exec 5>>config.log
-{
-cat <<_ASUNAME
-## --------- ##
-## Platform. ##
-## --------- ##
-
-hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
-/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
-
-/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
-/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
-/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
-/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
-/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
-/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
-
-_ASUNAME
-
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    $as_echo "PATH: $as_dir"
-  done
-IFS=$as_save_IFS
-
-} >&5
-
-cat >&5 <<_ACEOF
-
-
-## ----------- ##
-## Core tests. ##
-## ----------- ##
-
-_ACEOF
-
-
-# Keep a trace of the command line.
-# Strip out --no-create and --no-recursion so they do not pile up.
-# Strip out --silent because we don't want to record it for future runs.
-# Also quote any args containing shell meta-characters.
-# Make two passes to allow for proper duplicate-argument suppression.
-ac_configure_args=
-ac_configure_args0=
-ac_configure_args1=
-ac_must_keep_next=false
-for ac_pass in 1 2
-do
-  for ac_arg
-  do
-    case $ac_arg in
-    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
-    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
-    | -silent | --silent | --silen | --sile | --sil)
-      continue ;;
-    *\'*)
-      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
-    esac
-    case $ac_pass in
-    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
-    2)
-      as_fn_append ac_configure_args1 " '$ac_arg'"
-      if test $ac_must_keep_next = true; then
-	ac_must_keep_next=false # Got value, back to normal.
-      else
-	case $ac_arg in
-	  *=* | --config-cache | -C | -disable-* | --disable-* \
-	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
-	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
-	  | -with-* | --with-* | -without-* | --without-* | --x)
-	    case "$ac_configure_args0 " in
-	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
-	    esac
-	    ;;
-	  -* ) ac_must_keep_next=true ;;
-	esac
-      fi
-      as_fn_append ac_configure_args " '$ac_arg'"
-      ;;
-    esac
-  done
-done
-{ ac_configure_args0=; unset ac_configure_args0;}
-{ ac_configure_args1=; unset ac_configure_args1;}
-
-# When interrupted or exit'd, cleanup temporary files, and complete
-# config.log.  We remove comments because anyway the quotes in there
-# would cause problems or look ugly.
-# WARNING: Use '\'' to represent an apostrophe within the trap.
-# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
-trap 'exit_status=$?
-  # Save into config.log some information that might help in debugging.
-  {
-    echo
-
-    $as_echo "## ---------------- ##
-## Cache variables. ##
-## ---------------- ##"
-    echo
-    # The following way of writing the cache mishandles newlines in values,
-(
-  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
-    eval ac_val=\$$ac_var
-    case $ac_val in #(
-    *${as_nl}*)
-      case $ac_var in #(
-      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
-      esac
-      case $ac_var in #(
-      _ | IFS | as_nl) ;; #(
-      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
-      *) { eval $ac_var=; unset $ac_var;} ;;
-      esac ;;
-    esac
-  done
-  (set) 2>&1 |
-    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
-    *${as_nl}ac_space=\ *)
-      sed -n \
-	"s/'\''/'\''\\\\'\'''\''/g;
-	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
-      ;; #(
-    *)
-      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
-      ;;
-    esac |
-    sort
-)
-    echo
-
-    $as_echo "## ----------------- ##
-## Output variables. ##
-## ----------------- ##"
-    echo
-    for ac_var in $ac_subst_vars
-    do
-      eval ac_val=\$$ac_var
-      case $ac_val in
-      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
-      esac
-      $as_echo "$ac_var='\''$ac_val'\''"
-    done | sort
-    echo
-
-    if test -n "$ac_subst_files"; then
-      $as_echo "## ------------------- ##
-## File substitutions. ##
-## ------------------- ##"
-      echo
-      for ac_var in $ac_subst_files
-      do
-	eval ac_val=\$$ac_var
-	case $ac_val in
-	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
-	esac
-	$as_echo "$ac_var='\''$ac_val'\''"
-      done | sort
-      echo
-    fi
-
-    if test -s confdefs.h; then
-      $as_echo "## ----------- ##
-## confdefs.h. ##
-## ----------- ##"
-      echo
-      cat confdefs.h
-      echo
-    fi
-    test "$ac_signal" != 0 &&
-      $as_echo "$as_me: caught signal $ac_signal"
-    $as_echo "$as_me: exit $exit_status"
-  } >&5
-  rm -f core *.core core.conftest.* &&
-    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
-    exit $exit_status
-' 0
-for ac_signal in 1 2 13 15; do
-  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
-done
-ac_signal=0
-
-# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -f -r conftest* confdefs.h
-
-$as_echo "/* confdefs.h */" > confdefs.h
-
-# Predefined preprocessor variables.
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_NAME "$PACKAGE_NAME"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_VERSION "$PACKAGE_VERSION"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_STRING "$PACKAGE_STRING"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
-_ACEOF
-
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_URL "$PACKAGE_URL"
-_ACEOF
-
-
-# Let the site file select an alternate cache file if it wants to.
-# Prefer an explicitly selected file to automatically selected ones.
-ac_site_file1=NONE
-ac_site_file2=NONE
-if test -n "$CONFIG_SITE"; then
-  # We do not want a PATH search for config.site.
-  case $CONFIG_SITE in #((
-    -*)  ac_site_file1=./$CONFIG_SITE;;
-    */*) ac_site_file1=$CONFIG_SITE;;
-    *)   ac_site_file1=./$CONFIG_SITE;;
-  esac
-elif test "x$prefix" != xNONE; then
-  ac_site_file1=$prefix/share/config.site
-  ac_site_file2=$prefix/etc/config.site
-else
-  ac_site_file1=$ac_default_prefix/share/config.site
-  ac_site_file2=$ac_default_prefix/etc/config.site
-fi
-for ac_site_file in "$ac_site_file1" "$ac_site_file2"
-do
-  test "x$ac_site_file" = xNONE && continue
-  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
-$as_echo "$as_me: loading site script $ac_site_file" >&6;}
-    sed 's/^/| /' "$ac_site_file" >&5
-    . "$ac_site_file" \
-      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "failed to load site script $ac_site_file
-See \`config.log' for more details" "$LINENO" 5; }
-  fi
-done
-
-if test -r "$cache_file"; then
-  # Some versions of bash will fail to source /dev/null (special files
-  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
-  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
-$as_echo "$as_me: loading cache $cache_file" >&6;}
-    case $cache_file in
-      [\\/]* | ?:[\\/]* ) . "$cache_file";;
-      *)                      . "./$cache_file";;
-    esac
-  fi
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
-$as_echo "$as_me: creating cache $cache_file" >&6;}
-  >$cache_file
-fi
-
-# Check that the precious variables saved in the cache have kept the same
-# value.
-ac_cache_corrupted=false
-for ac_var in $ac_precious_vars; do
-  eval ac_old_set=\$ac_cv_env_${ac_var}_set
-  eval ac_new_set=\$ac_env_${ac_var}_set
-  eval ac_old_val=\$ac_cv_env_${ac_var}_value
-  eval ac_new_val=\$ac_env_${ac_var}_value
-  case $ac_old_set,$ac_new_set in
-    set,)
-      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
-      ac_cache_corrupted=: ;;
-    ,set)
-      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
-$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
-      ac_cache_corrupted=: ;;
-    ,);;
-    *)
-      if test "x$ac_old_val" != "x$ac_new_val"; then
-	# differences in whitespace do not lead to failure.
-	ac_old_val_w=`echo x $ac_old_val`
-	ac_new_val_w=`echo x $ac_new_val`
-	if test "$ac_old_val_w" != "$ac_new_val_w"; then
-	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
-$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
-	  ac_cache_corrupted=:
-	else
-	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
-$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
-	  eval $ac_var=\$ac_old_val
-	fi
-	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
-$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
-	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
-$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
-      fi;;
-  esac
-  # Pass precious variables to config.status.
-  if test "$ac_new_set" = set; then
-    case $ac_new_val in
-    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
-    *) ac_arg=$ac_var=$ac_new_val ;;
-    esac
-    case " $ac_configure_args " in
-      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
-      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
-    esac
-  fi
-done
-if $ac_cache_corrupted; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
-$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
-  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
-fi
-## -------------------- ##
-## Main body of script. ##
-## -------------------- ##
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
-
-###########################
-# find compiler and flags #
-###########################
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking location of R" >&5
-$as_echo_n "checking location of R... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${R_HOME}" >&5
-$as_echo "${R_HOME}" >&6; }
-
-# set up CPP flags
-# find the compiler and compiler flags used by R.
-: ${R_HOME=`R HOME`}
-if test -z "${R_HOME}"; then
-    echo "could not determine R_HOME"
-    exit 1
-fi
-CC=`"${R_HOME}/bin/R" CMD config CC`
-CXX=`"${R_HOME}/bin/R" CMD config CXX11`
-
-# LightGBM-specific flags
-LGB_CPPFLAGS=""
-
-#########
-# Eigen #
-#########
-
-LGB_CPPFLAGS="${LGB_CPPFLAGS} -DEIGEN_MPL2_ONLY"
-
-###############
-# MM_PREFETCH #
-###############
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether MM_PREFETCH works" >&5
-$as_echo_n "checking whether MM_PREFETCH works... " >&6; }
-ac_mmprefetch=no
-ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-                #include <xmmintrin.h>
-
-int
-main ()
-{
-
-                int a = 0;
-                _mm_prefetch(&a, _MM_HINT_NTA);
-                return 0;
-
-
-  ;
-  return 0;
-}
-
-
-_ACEOF
-${CXX} -o conftest conftest.cpp 2>/dev/null && ./conftest && ac_mmprefetch=yes
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_mmprefetch}" >&5
-$as_echo "${ac_mmprefetch}" >&6; }
-if test "${ac_mmprefetch}" = yes; then
-    LGB_CPPFLAGS+=" -DMM_PREFETCH=1"
-fi
-
-############
-# MM_ALLOC #
-############
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether MM_MALLOC works" >&5
-$as_echo_n "checking whether MM_MALLOC works... " >&6; }
-ac_mm_malloc=no
-ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-                #include <mm_malloc.h>
-
-int
-main ()
-{
-
-                char *a = (char*)_mm_malloc(8, 16);
-                _mm_free(a);
-                return 0;
-
-
-  ;
-  return 0;
-}
-
-
-_ACEOF
-${CXX} -o conftest conftest.cpp 2>/dev/null && ./conftest && ac_mm_malloc=yes
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_mm_malloc}" >&5
-$as_echo "${ac_mm_malloc}" >&6; }
-if test "${ac_mm_malloc}" = yes; then
-    LGB_CPPFLAGS+=" -DMM_MALLOC=1"
-fi
-
-##########
-# OpenMP #
-##########
-
-OPENMP_CXXFLAGS=""
-
-if test `uname -s` = "Linux"
-then
-    OPENMP_CXXFLAGS="\$(SHLIB_OPENMP_CXXFLAGS)"
-fi
-
-if test `uname -s` = "Darwin"
-then
-    OPENMP_CXXFLAGS='-Xclang -fopenmp'
-    OPENMP_LIB='-lomp'
-    ac_pkg_openmp=no
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether OpenMP will work in a package" >&5
-$as_echo_n "checking whether OpenMP will work in a package... " >&6; }
-    ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-                    #include <omp.h>
-
-int
-main ()
-{
-
-                    return (omp_get_max_threads() <= 1);
-
-
-  ;
-  return 0;
-}
-
-
-_ACEOF
-    ${CC} -o conftest conftest.c ${OPENMP_LIB} ${OPENMP_CXXFLAGS} 2>/dev/null && ./conftest && ac_pkg_openmp=yes
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${ac_pkg_openmp}" >&5
-$as_echo "${ac_pkg_openmp}" >&6; }
-    if test "${ac_pkg_openmp}" = no; then
-        OPENMP_CXXFLAGS=''
-        OPENMP_LIB=''
-        echo '***********************************************************************************************'
-        echo ' OpenMP is unavailable on this macOS system. LightGBM code will run single-threaded as a result.'
-        echo ' To use all CPU cores for training jobs, you should install OpenMP by running'
-        echo ''
-        echo '     brew install libomp'
-        echo '***********************************************************************************************'
-    fi
-fi
-
-# substitute variables from this script into Makevars.in
-
-
-
-ac_config_files="$ac_config_files src/Makevars"
-
-
-# write out Autoconf output
-cat >confcache <<\_ACEOF
-# This file is a shell script that caches the results of configure
-# tests run on this system so they can be shared between configure
-# scripts and configure runs, see configure's option --config-cache.
-# It is not useful on other systems.  If it contains results you don't
-# want to keep, you may remove or edit it.
-#
-# config.status only pays attention to the cache file if you give it
-# the --recheck option to rerun configure.
-#
-# `ac_cv_env_foo' variables (set or unset) will be overridden when
-# loading this file, other *unset* `ac_cv_foo' will be assigned the
-# following values.
-
-_ACEOF
-
-# The following way of writing the cache mishandles newlines in values,
-# but we know of no workaround that is simple, portable, and efficient.
-# So, we kill variables containing newlines.
-# Ultrix sh set writes to stderr and can't be redirected directly,
-# and sets the high bit in the cache file unless we assign to the vars.
-(
-  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
-    eval ac_val=\$$ac_var
-    case $ac_val in #(
-    *${as_nl}*)
-      case $ac_var in #(
-      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
-      esac
-      case $ac_var in #(
-      _ | IFS | as_nl) ;; #(
-      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
-      *) { eval $ac_var=; unset $ac_var;} ;;
-      esac ;;
-    esac
-  done
-
-  (set) 2>&1 |
-    case $as_nl`(ac_space=' '; set) 2>&1` in #(
-    *${as_nl}ac_space=\ *)
-      # `set' does not quote correctly, so add quotes: double-quote
-      # substitution turns \\\\ into \\, and sed turns \\ into \.
-      sed -n \
-	"s/'/'\\\\''/g;
-	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
-      ;; #(
-    *)
-      # `set' quotes correctly as required by POSIX, so do not add quotes.
-      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
-      ;;
-    esac |
-    sort
-) |
-  sed '
-     /^ac_cv_env_/b end
-     t clear
-     :clear
-     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
-     t end
-     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
-     :end' >>confcache
-if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
-  if test -w "$cache_file"; then
-    if test "x$cache_file" != "x/dev/null"; then
-      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
-$as_echo "$as_me: updating cache $cache_file" >&6;}
-      if test ! -f "$cache_file" || test -h "$cache_file"; then
-	cat confcache >"$cache_file"
-      else
-        case $cache_file in #(
-        */* | ?:*)
-	  mv -f confcache "$cache_file"$$ &&
-	  mv -f "$cache_file"$$ "$cache_file" ;; #(
-        *)
-	  mv -f confcache "$cache_file" ;;
-	esac
-      fi
-    fi
-  else
-    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
-$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
-  fi
-fi
-rm -f confcache
-
-test "x$prefix" = xNONE && prefix=$ac_default_prefix
-# Let make expand exec_prefix.
-test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-
-# Transform confdefs.h into DEFS.
-# Protect against shell expansion while executing Makefile rules.
-# Protect against Makefile macro expansion.
-#
-# If the first sed substitution is executed (which looks for macros that
-# take arguments), then branch to the quote section.  Otherwise,
-# look for a macro that doesn't take arguments.
-ac_script='
-:mline
-/\\$/{
- N
- s,\\\n,,
- b mline
-}
-t clear
-:clear
-s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*([^)]*)\)[	 ]*\(.*\)/-D\1=\2/g
-t quote
-s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)/-D\1=\2/g
-t quote
-b any
-:quote
-s/[	 `~#$^&*(){}\\|;'\''"<>?]/\\&/g
-s/\[/\\&/g
-s/\]/\\&/g
-s/\$/$$/g
-H
-:any
-${
-	g
-	s/^\n//
-	s/\n/ /g
-	p
-}
-'
-DEFS=`sed -n "$ac_script" confdefs.h`
-
-
-ac_libobjs=
-ac_ltlibobjs=
-U=
-for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
-  # 1. Remove the extension, and $U if already installed.
-  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
-  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
-  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
-  #    will be set to the directory where LIBOBJS objects are built.
-  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
-  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
-done
-LIBOBJS=$ac_libobjs
-
-LTLIBOBJS=$ac_ltlibobjs
-
-
-
-: "${CONFIG_STATUS=./config.status}"
-ac_write_fail=0
-ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
-$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
-as_write_fail=0
-cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
-#! $SHELL
-# Generated by $as_me.
-# Run this file to recreate the current configuration.
-# Compiler output produced by configure, useful for debugging
-# configure, is in config.log if it exists.
-
-debug=false
-ac_cs_recheck=false
-ac_cs_silent=false
-
-SHELL=\${CONFIG_SHELL-$SHELL}
-export SHELL
-_ASEOF
-cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
-## -------------------- ##
-## M4sh Initialization. ##
-## -------------------- ##
-
-# Be more Bourne compatible
-DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
-  emulate sh
-  NULLCMD=:
-  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
-  # is contrary to our usage.  Disable this feature.
-  alias -g '${1+"$@"}'='"$@"'
-  setopt NO_GLOB_SUBST
-else
-  case `(set -o) 2>/dev/null` in #(
-  *posix*) :
-    set -o posix ;; #(
-  *) :
-     ;;
-esac
-fi
-
-
-as_nl='
-'
-export as_nl
-# Printing a long string crashes Solaris 7 /usr/bin/printf.
-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-# Prefer a ksh shell builtin over an external printf program on Solaris,
-# but without wasting forks for bash or zsh.
-if test -z "$BASH_VERSION$ZSH_VERSION" \
-    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
-  as_echo='print -r --'
-  as_echo_n='print -rn --'
-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
-  as_echo='printf %s\n'
-  as_echo_n='printf %s'
-else
-  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
-    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
-    as_echo_n='/usr/ucb/echo -n'
-  else
-    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
-    as_echo_n_body='eval
-      arg=$1;
-      case $arg in #(
-      *"$as_nl"*)
-	expr "X$arg" : "X\\(.*\\)$as_nl";
-	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
-      esac;
-      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
-    '
-    export as_echo_n_body
-    as_echo_n='sh -c $as_echo_n_body as_echo'
-  fi
-  export as_echo_body
-  as_echo='sh -c $as_echo_body as_echo'
-fi
-
-# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
-  PATH_SEPARATOR=:
-  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
-    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
-      PATH_SEPARATOR=';'
-  }
-fi
-
-
-# IFS
-# We need space, tab and new line, in precisely that order.  Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-IFS=" ""	$as_nl"
-
-# Find who we are.  Look in the path if we contain no directory separator.
-as_myself=
-case $0 in #((
-  *[\\/]* ) as_myself=$0 ;;
-  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-  done
-IFS=$as_save_IFS
-
-     ;;
-esac
-# We did not find ourselves, most probably we were run as `sh COMMAND'
-# in which case we are not to be found in the path.
-if test "x$as_myself" = x; then
-  as_myself=$0
-fi
-if test ! -f "$as_myself"; then
-  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
-  exit 1
-fi
-
-# Unset variables that we do not need and which cause bugs (e.g. in
-# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
-# suppresses any "Segmentation fault" message there.  '((' could
-# trigger a bug in pdksh 5.2.14.
-for as_var in BASH_ENV ENV MAIL MAILPATH
-do eval test x\${$as_var+set} = xset \
-  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
-
-
-# as_fn_error STATUS ERROR [LINENO LOG_FD]
-# ----------------------------------------
-# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
-# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
-# script with STATUS, using 1 if that was 0.
-as_fn_error ()
-{
-  as_status=$1; test $as_status -eq 0 && as_status=1
-  if test "$4"; then
-    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
-  fi
-  $as_echo "$as_me: error: $2" >&2
-  as_fn_exit $as_status
-} # as_fn_error
-
-
-# as_fn_set_status STATUS
-# -----------------------
-# Set $? to STATUS, without forking.
-as_fn_set_status ()
-{
-  return $1
-} # as_fn_set_status
-
-# as_fn_exit STATUS
-# -----------------
-# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
-as_fn_exit ()
-{
-  set +e
-  as_fn_set_status $1
-  exit $1
-} # as_fn_exit
-
-# as_fn_unset VAR
-# ---------------
-# Portably unset VAR.
-as_fn_unset ()
-{
-  { eval $1=; unset $1;}
-}
-as_unset=as_fn_unset
-# as_fn_append VAR VALUE
-# ----------------------
-# Append the text in VALUE to the end of the definition contained in VAR. Take
-# advantage of any shell optimizations that allow amortized linear growth over
-# repeated appends, instead of the typical quadratic growth present in naive
-# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
-  eval 'as_fn_append ()
-  {
-    eval $1+=\$2
-  }'
-else
-  as_fn_append ()
-  {
-    eval $1=\$$1\$2
-  }
-fi # as_fn_append
-
-# as_fn_arith ARG...
-# ------------------
-# Perform arithmetic evaluation on the ARGs, and store the result in the
-# global $as_val. Take advantage of shells that can avoid forks. The arguments
-# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
-  eval 'as_fn_arith ()
-  {
-    as_val=$(( $* ))
-  }'
-else
-  as_fn_arith ()
-  {
-    as_val=`expr "$@" || test $? -eq 1`
-  }
-fi # as_fn_arith
-
-
-if expr a : '\(a\)' >/dev/null 2>&1 &&
-   test "X`expr 00001 : '.*\(...\)'`" = X001; then
-  as_expr=expr
-else
-  as_expr=false
-fi
-
-if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
-  as_basename=basename
-else
-  as_basename=false
-fi
-
-if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
-  as_dirname=dirname
-else
-  as_dirname=false
-fi
-
-as_me=`$as_basename -- "$0" ||
-$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
-	 X"$0" : 'X\(//\)$' \| \
-	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$0" |
-    sed '/^.*\/\([^/][^/]*\)\/*$/{
-	    s//\1/
-	    q
-	  }
-	  /^X\/\(\/\/\)$/{
-	    s//\1/
-	    q
-	  }
-	  /^X\/\(\/\).*/{
-	    s//\1/
-	    q
-	  }
-	  s/.*/./; q'`
-
-# Avoid depending upon Character Ranges.
-as_cr_letters='abcdefghijklmnopqrstuvwxyz'
-as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-as_cr_Letters=$as_cr_letters$as_cr_LETTERS
-as_cr_digits='0123456789'
-as_cr_alnum=$as_cr_Letters$as_cr_digits
-
-ECHO_C= ECHO_N= ECHO_T=
-case `echo -n x` in #(((((
--n*)
-  case `echo 'xy\c'` in
-  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
-  xy)  ECHO_C='\c';;
-  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
-       ECHO_T='	';;
-  esac;;
-*)
-  ECHO_N='-n';;
-esac
-
-rm -f conf$$ conf$$.exe conf$$.file
-if test -d conf$$.dir; then
-  rm -f conf$$.dir/conf$$.file
-else
-  rm -f conf$$.dir
-  mkdir conf$$.dir 2>/dev/null
-fi
-if (echo >conf$$.file) 2>/dev/null; then
-  if ln -s conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s='ln -s'
-    # ... but there are two gotchas:
-    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
-    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
-    # In both cases, we have to default to `cp -pR'.
-    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
-      as_ln_s='cp -pR'
-  elif ln conf$$.file conf$$ 2>/dev/null; then
-    as_ln_s=ln
-  else
-    as_ln_s='cp -pR'
-  fi
-else
-  as_ln_s='cp -pR'
-fi
-rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
-rmdir conf$$.dir 2>/dev/null
-
-
-# as_fn_mkdir_p
-# -------------
-# Create "$as_dir" as a directory, including parents if necessary.
-as_fn_mkdir_p ()
-{
-
-  case $as_dir in #(
-  -*) as_dir=./$as_dir;;
-  esac
-  test -d "$as_dir" || eval $as_mkdir_p || {
-    as_dirs=
-    while :; do
-      case $as_dir in #(
-      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
-      *) as_qdir=$as_dir;;
-      esac
-      as_dirs="'$as_qdir' $as_dirs"
-      as_dir=`$as_dirname -- "$as_dir" ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-	 X"$as_dir" : 'X\(//\)[^/]' \| \
-	 X"$as_dir" : 'X\(//\)$' \| \
-	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-	    s//\1/
-	    q
-	  }
-	  /^X\(\/\/\)[^/].*/{
-	    s//\1/
-	    q
-	  }
-	  /^X\(\/\/\)$/{
-	    s//\1/
-	    q
-	  }
-	  /^X\(\/\).*/{
-	    s//\1/
-	    q
-	  }
-	  s/.*/./; q'`
-      test -d "$as_dir" && break
-    done
-    test -z "$as_dirs" || eval "mkdir $as_dirs"
-  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
-
-
-} # as_fn_mkdir_p
-if mkdir -p . 2>/dev/null; then
-  as_mkdir_p='mkdir -p "$as_dir"'
-else
-  test -d ./-p && rmdir ./-p
-  as_mkdir_p=false
-fi
-
-
-# as_fn_executable_p FILE
-# -----------------------
-# Test if FILE is an executable regular file.
-as_fn_executable_p ()
-{
-  test -f "$1" && test -x "$1"
-} # as_fn_executable_p
-as_test_x='test -x'
-as_executable_p=as_fn_executable_p
-
-# Sed expression to map a string onto a valid CPP name.
-as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
-
-# Sed expression to map a string onto a valid variable name.
-as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
-
-
-exec 6>&1
-## ----------------------------------- ##
-## Main body of $CONFIG_STATUS script. ##
-## ----------------------------------- ##
-_ASEOF
-test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# Save the log message, to keep $0 and so on meaningful, and to
-# report actual input values of CONFIG_FILES etc. instead of their
-# values after options handling.
-ac_log="
-This file was extended by lightgbm $as_me 3.2.1.99, which was
-generated by GNU Autoconf 2.69.  Invocation command line was
-
-  CONFIG_FILES    = $CONFIG_FILES
-  CONFIG_HEADERS  = $CONFIG_HEADERS
-  CONFIG_LINKS    = $CONFIG_LINKS
-  CONFIG_COMMANDS = $CONFIG_COMMANDS
-  $ $0 $@
-
-on `(hostname || uname -n) 2>/dev/null | sed 1q`
-"
-
-_ACEOF
-
-case $ac_config_files in *"
-"*) set x $ac_config_files; shift; ac_config_files=$*;;
-esac
-
-
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-# Files that config.status was made for.
-config_files="$ac_config_files"
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-ac_cs_usage="\
-\`$as_me' instantiates files and other configuration actions
-from templates according to the current configuration.  Unless the files
-and actions are specified as TAGs, all are instantiated by default.
-
-Usage: $0 [OPTION]... [TAG]...
-
-  -h, --help       print this help, then exit
-  -V, --version    print version number and configuration settings, then exit
-      --config     print configuration, then exit
-  -q, --quiet, --silent
-                   do not print progress messages
-  -d, --debug      don't remove temporary files
-      --recheck    update $as_me by reconfiguring in the same conditions
-      --file=FILE[:TEMPLATE]
-                   instantiate the configuration file FILE
-
-Configuration files:
-$config_files
-
-Report bugs to the package provider."
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
-ac_cs_version="\\
-lightgbm config.status 3.2.1.99
-configured by $0, generated by GNU Autoconf 2.69,
-  with options \\"\$ac_cs_config\\"
-
-Copyright (C) 2012 Free Software Foundation, Inc.
-This config.status script is free software; the Free Software Foundation
-gives unlimited permission to copy, distribute and modify it."
-
-ac_pwd='$ac_pwd'
-srcdir='$srcdir'
-test -n "\$AWK" || AWK=awk
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# The default lists apply if the user does not specify any file.
-ac_need_defaults=:
-while test $# != 0
-do
-  case $1 in
-  --*=?*)
-    ac_option=`expr "X$1" : 'X\([^=]*\)='`
-    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
-    ac_shift=:
-    ;;
-  --*=)
-    ac_option=`expr "X$1" : 'X\([^=]*\)='`
-    ac_optarg=
-    ac_shift=:
-    ;;
-  *)
-    ac_option=$1
-    ac_optarg=$2
-    ac_shift=shift
-    ;;
-  esac
-
-  case $ac_option in
-  # Handling of the options.
-  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
-    ac_cs_recheck=: ;;
-  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
-    $as_echo "$ac_cs_version"; exit ;;
-  --config | --confi | --conf | --con | --co | --c )
-    $as_echo "$ac_cs_config"; exit ;;
-  --debug | --debu | --deb | --de | --d | -d )
-    debug=: ;;
-  --file | --fil | --fi | --f )
-    $ac_shift
-    case $ac_optarg in
-    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
-    '') as_fn_error $? "missing file argument" ;;
-    esac
-    as_fn_append CONFIG_FILES " '$ac_optarg'"
-    ac_need_defaults=false;;
-  --he | --h |  --help | --hel | -h )
-    $as_echo "$ac_cs_usage"; exit ;;
-  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
-  | -silent | --silent | --silen | --sile | --sil | --si | --s)
-    ac_cs_silent=: ;;
-
-  # This is an error.
-  -*) as_fn_error $? "unrecognized option: \`$1'
-Try \`$0 --help' for more information." ;;
-
-  *) as_fn_append ac_config_targets " $1"
-     ac_need_defaults=false ;;
-
-  esac
-  shift
-done
-
-ac_configure_extra_args=
-
-if $ac_cs_silent; then
-  exec 6>/dev/null
-  ac_configure_extra_args="$ac_configure_extra_args --silent"
-fi
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-if \$ac_cs_recheck; then
-  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
-  shift
-  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
-  CONFIG_SHELL='$SHELL'
-  export CONFIG_SHELL
-  exec "\$@"
-fi
-
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-exec 5>>config.log
-{
-  echo
-  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
-## Running $as_me. ##
-_ASBOX
-  $as_echo "$ac_log"
-} >&5
-
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-
-# Handling of arguments.
-for ac_config_target in $ac_config_targets
-do
-  case $ac_config_target in
-    "src/Makevars") CONFIG_FILES="$CONFIG_FILES src/Makevars" ;;
-
-  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
-  esac
-done
-
-
-# If the user did not use the arguments to specify the items to instantiate,
-# then the envvar interface is used.  Set only those that are not.
-# We use the long form for the default assignment because of an extremely
-# bizarre bug on SunOS 4.1.3.
-if $ac_need_defaults; then
-  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
-fi
-
-# Have a temporary directory for convenience.  Make it in the build tree
-# simply because there is no reason against having it here, and in addition,
-# creating and moving files from /tmp can sometimes cause problems.
-# Hook for its removal unless debugging.
-# Note that there is a small window in which the directory will not be cleaned:
-# after its creation but before its name has been assigned to `$tmp'.
-$debug ||
-{
-  tmp= ac_tmp=
-  trap 'exit_status=$?
-  : "${ac_tmp:=$tmp}"
-  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
-' 0
-  trap 'as_fn_exit 1' 1 2 13 15
-}
-# Create a (secure) tmp directory for tmp files.
-
-{
-  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
-  test -d "$tmp"
-}  ||
-{
-  tmp=./conf$$-$RANDOM
-  (umask 077 && mkdir "$tmp")
-} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
-ac_tmp=$tmp
-
-# Set up the scripts for CONFIG_FILES section.
-# No need to generate them if there are no CONFIG_FILES.
-# This happens for instance with `./config.status config.h'.
-if test -n "$CONFIG_FILES"; then
-
-
-ac_cr=`echo X | tr X '\015'`
-# On cygwin, bash can eat \r inside `` if the user requested igncr.
-# But we know of no other shell where ac_cr would be empty at this
-# point, so we can use a bashism as a fallback.
-if test "x$ac_cr" = x; then
-  eval ac_cr=\$\'\\r\'
-fi
-ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
-if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
-  ac_cs_awk_cr='\\r'
-else
-  ac_cs_awk_cr=$ac_cr
-fi
-
-echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
-_ACEOF
-
-
-{
-  echo "cat >conf$$subs.awk <<_ACEOF" &&
-  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
-  echo "_ACEOF"
-} >conf$$subs.sh ||
-  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
-ac_delim='%!_!# '
-for ac_last_try in false false false false false :; do
-  . ./conf$$subs.sh ||
-    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-
-  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
-  if test $ac_delim_n = $ac_delim_num; then
-    break
-  elif $ac_last_try; then
-    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
-  else
-    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
-  fi
-done
-rm -f conf$$subs.sh
-
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
-_ACEOF
-sed -n '
-h
-s/^/S["/; s/!.*/"]=/
-p
-g
-s/^[^!]*!//
-:repl
-t repl
-s/'"$ac_delim"'$//
-t delim
-:nl
-h
-s/\(.\{148\}\)..*/\1/
-t more1
-s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
-p
-n
-b repl
-:more1
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t nl
-:delim
-h
-s/\(.\{148\}\)..*/\1/
-t more2
-s/["\\]/\\&/g; s/^/"/; s/$/"/
-p
-b
-:more2
-s/["\\]/\\&/g; s/^/"/; s/$/"\\/
-p
-g
-s/.\{148\}//
-t delim
-' <conf$$subs.awk | sed '
-/^[^""]/{
-  N
-  s/\n//
-}
-' >>$CONFIG_STATUS || ac_write_fail=1
-rm -f conf$$subs.awk
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-_ACAWK
-cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
-  for (key in S) S_is_set[key] = 1
-  FS = ""
-
-}
-{
-  line = $ 0
-  nfields = split(line, field, "@")
-  substed = 0
-  len = length(field[1])
-  for (i = 2; i < nfields; i++) {
-    key = field[i]
-    keylen = length(key)
-    if (S_is_set[key]) {
-      value = S[key]
-      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
-      len += length(value) + length(field[++i])
-      substed = 1
-    } else
-      len += 1 + keylen
-  }
-
-  print line
-}
-
-_ACAWK
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
-  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
-else
-  cat
-fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
-  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
-_ACEOF
-
-# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
-# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
-# trailing colons and then remove the whole line if VPATH becomes empty
-# (actually we leave an empty line to preserve line numbers).
-if test "x$srcdir" = x.; then
-  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
-h
-s///
-s/^/:/
-s/[	 ]*$/:/
-s/:\$(srcdir):/:/g
-s/:\${srcdir}:/:/g
-s/:@srcdir@:/:/g
-s/^:*//
-s/:*$//
-x
-s/\(=[	 ]*\).*/\1/
-G
-s/\n//
-s/^[^=]*=[	 ]*$//
-}'
-fi
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-fi # test -n "$CONFIG_FILES"
-
-
-eval set X "  :F $CONFIG_FILES      "
-shift
-for ac_tag
-do
-  case $ac_tag in
-  :[FHLC]) ac_mode=$ac_tag; continue;;
-  esac
-  case $ac_mode$ac_tag in
-  :[FHL]*:*);;
-  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
-  :[FH]-) ac_tag=-:-;;
-  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
-  esac
-  ac_save_IFS=$IFS
-  IFS=:
-  set x $ac_tag
-  IFS=$ac_save_IFS
-  shift
-  ac_file=$1
-  shift
-
-  case $ac_mode in
-  :L) ac_source=$1;;
-  :[FH])
-    ac_file_inputs=
-    for ac_f
-    do
-      case $ac_f in
-      -) ac_f="$ac_tmp/stdin";;
-      *) # Look for the file first in the build tree, then in the source tree
-	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
-	 # because $ac_f cannot contain `:'.
-	 test -f "$ac_f" ||
-	   case $ac_f in
-	   [\\/$]*) false;;
-	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
-	   esac ||
-	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
-      esac
-      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
-      as_fn_append ac_file_inputs " '$ac_f'"
-    done
-
-    # Let's still pretend it is `configure' which instantiates (i.e., don't
-    # use $as_me), people would be surprised to read:
-    #    /* config.h.  Generated by config.status.  */
-    configure_input='Generated from '`
-	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
-	`' by configure.'
-    if test x"$ac_file" != x-; then
-      configure_input="$ac_file.  $configure_input"
-      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
-$as_echo "$as_me: creating $ac_file" >&6;}
-    fi
-    # Neutralize special characters interpreted by sed in replacement strings.
-    case $configure_input in #(
-    *\&* | *\|* | *\\* )
-       ac_sed_conf_input=`$as_echo "$configure_input" |
-       sed 's/[\\\\&|]/\\\\&/g'`;; #(
-    *) ac_sed_conf_input=$configure_input;;
-    esac
-
-    case $ac_tag in
-    *:-:* | *:-) cat >"$ac_tmp/stdin" \
-      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
-    esac
-    ;;
-  esac
-
-  ac_dir=`$as_dirname -- "$ac_file" ||
-$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-	 X"$ac_file" : 'X\(//\)[^/]' \| \
-	 X"$ac_file" : 'X\(//\)$' \| \
-	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$ac_file" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
-	    s//\1/
-	    q
-	  }
-	  /^X\(\/\/\)[^/].*/{
-	    s//\1/
-	    q
-	  }
-	  /^X\(\/\/\)$/{
-	    s//\1/
-	    q
-	  }
-	  /^X\(\/\).*/{
-	    s//\1/
-	    q
-	  }
-	  s/.*/./; q'`
-  as_dir="$ac_dir"; as_fn_mkdir_p
-  ac_builddir=.
-
-case "$ac_dir" in
-.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
-*)
-  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
-  # A ".." for each directory in $ac_dir_suffix.
-  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
-  case $ac_top_builddir_sub in
-  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
-  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
-  esac ;;
-esac
-ac_abs_top_builddir=$ac_pwd
-ac_abs_builddir=$ac_pwd$ac_dir_suffix
-# for backward compatibility:
-ac_top_builddir=$ac_top_build_prefix
-
-case $srcdir in
-  .)  # We are building in place.
-    ac_srcdir=.
-    ac_top_srcdir=$ac_top_builddir_sub
-    ac_abs_top_srcdir=$ac_pwd ;;
-  [\\/]* | ?:[\\/]* )  # Absolute name.
-    ac_srcdir=$srcdir$ac_dir_suffix;
-    ac_top_srcdir=$srcdir
-    ac_abs_top_srcdir=$srcdir ;;
-  *) # Relative name.
-    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
-    ac_top_srcdir=$ac_top_build_prefix$srcdir
-    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
-esac
-ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
-
-
-  case $ac_mode in
-  :F)
-  #
-  # CONFIG_FILE
-  #
-
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-# If the template does not know about datarootdir, expand it.
-# FIXME: This hack should be removed a few years after 2.60.
-ac_datarootdir_hack=; ac_datarootdir_seen=
-ac_sed_dataroot='
-/datarootdir/ {
-  p
-  q
-}
-/@datadir@/p
-/@docdir@/p
-/@infodir@/p
-/@localedir@/p
-/@mandir@/p'
-case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
-*datarootdir*) ac_datarootdir_seen=yes;;
-*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
-$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
-_ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-  ac_datarootdir_hack='
-  s&@datadir@&$datadir&g
-  s&@docdir@&$docdir&g
-  s&@infodir@&$infodir&g
-  s&@localedir@&$localedir&g
-  s&@mandir@&$mandir&g
-  s&\\\${datarootdir}&$datarootdir&g' ;;
-esac
-_ACEOF
-
-# Neutralize VPATH when `$srcdir' = `.'.
-# Shell code in configure.ac might set extrasub.
-# FIXME: do we really want to maintain this feature?
-cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_sed_extra="$ac_vpsub
-$extrasub
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
-:t
-/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
-s|@configure_input@|$ac_sed_conf_input|;t t
-s&@top_builddir@&$ac_top_builddir_sub&;t t
-s&@top_build_prefix@&$ac_top_build_prefix&;t t
-s&@srcdir@&$ac_srcdir&;t t
-s&@abs_srcdir@&$ac_abs_srcdir&;t t
-s&@top_srcdir@&$ac_top_srcdir&;t t
-s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
-s&@builddir@&$ac_builddir&;t t
-s&@abs_builddir@&$ac_abs_builddir&;t t
-s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
-$ac_datarootdir_hack
-"
-eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
-  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
-
-test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
-  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
-  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
-      "$ac_tmp/out"`; test -z "$ac_out"; } &&
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined.  Please make sure it is defined" >&5
-$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
-which seems to be undefined.  Please make sure it is defined" >&2;}
-
-  rm -f "$ac_tmp/stdin"
-  case $ac_file in
-  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
-  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
-  esac \
-  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
- ;;
-
-
-
-  esac
-
-done # for ac_tag
-
-
-as_fn_exit 0
-_ACEOF
-ac_clean_files=$ac_clean_files_save
-
-test $ac_write_fail = 0 ||
-  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
-
-
-# configure is writing to config.log, and then calls config.status.
-# config.status does its own redirection, appending to config.log.
-# Unfortunately, on DOS this fails, as config.log is still kept open
-# by configure, so config.status won't be able to write to it; its
-# output is simply discarded.  So we exec the FD to /dev/null,
-# effectively closing config.log, so it can be properly (re)opened and
-# appended to by config.status.  When coming back to configure, we
-# need to make the FD available again.
-if test "$no_create" != yes; then
-  ac_cs_success=:
-  ac_config_status_args=
-  test "$silent" = yes &&
-    ac_config_status_args="$ac_config_status_args --quiet"
-  exec 5>/dev/null
-  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
-  exec 5>>config.log
-  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
-  # would make configure fail if this is the last instruction.
-  $ac_cs_success || as_fn_exit 1
-fi
-if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
-$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
-fi
-
diff --git a/R-package/configure.ac b/R-package/configure.ac
deleted file mode 100644
index afcde3f2f..000000000
--- a/R-package/configure.ac
+++ /dev/null
@@ -1,140 +0,0 @@
-### configure.ac                    -*- Autoconf -*-
-# Template used by Autoconf to generate 'configure' script. For more see:
-#   * https://unconj.ca/blog/an-autoconf-primer-for-r-package-authors.html
-#   * https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Configure-and-cleanup
-
-AC_PREREQ(2.69)
-AC_INIT([lightgbm], [~~VERSION~~], [], [lightgbm], [])
-
-###########################
-# find compiler and flags #
-###########################
-
-AC_MSG_CHECKING([location of R])
-AC_MSG_RESULT([${R_HOME}])
-
-# set up CPP flags
-# find the compiler and compiler flags used by R.
-: ${R_HOME=`R HOME`}
-if test -z "${R_HOME}"; then
-    echo "could not determine R_HOME"
-    exit 1
-fi
-CC=`"${R_HOME}/bin/R" CMD config CC`
-CXX=`"${R_HOME}/bin/R" CMD config CXX11`
-
-# LightGBM-specific flags
-LGB_CPPFLAGS=""
-
-#########
-# Eigen #
-#########
-
-LGB_CPPFLAGS="${LGB_CPPFLAGS} -DEIGEN_MPL2_ONLY"
-
-###############
-# MM_PREFETCH #
-###############
-
-AC_MSG_CHECKING([whether MM_PREFETCH works])
-ac_mmprefetch=no
-AC_LANG(C++)
-AC_LANG_CONFTEST(
-    [
-        AC_LANG_PROGRAM(
-            [[
-                #include <xmmintrin.h>
-            ]],
-            [[
-                int a = 0;
-                _mm_prefetch(&a, _MM_HINT_NTA);
-                return 0;
-            ]]
-        )
-    ]
-)
-${CXX} -o conftest conftest.cpp 2>/dev/null && ./conftest && ac_mmprefetch=yes
-AC_MSG_RESULT([${ac_mmprefetch}])
-if test "${ac_mmprefetch}" = yes; then
-    LGB_CPPFLAGS+=" -DMM_PREFETCH=1"
-fi
-
-############
-# MM_ALLOC #
-############
-
-AC_MSG_CHECKING([whether MM_MALLOC works])
-ac_mm_malloc=no
-AC_LANG(C++)
-AC_LANG_CONFTEST(
-    [
-        AC_LANG_PROGRAM(
-            [[
-                #include <mm_malloc.h>
-            ]],
-            [[
-                char *a = (char*)_mm_malloc(8, 16);
-                _mm_free(a);
-                return 0;
-            ]]
-        )
-    ]
-)
-${CXX} -o conftest conftest.cpp 2>/dev/null && ./conftest && ac_mm_malloc=yes
-AC_MSG_RESULT([${ac_mm_malloc}])
-if test "${ac_mm_malloc}" = yes; then
-    LGB_CPPFLAGS+=" -DMM_MALLOC=1"
-fi
-
-##########
-# OpenMP #
-##########
-
-OPENMP_CXXFLAGS=""
-
-if test `uname -s` = "Linux"
-then
-    OPENMP_CXXFLAGS="\$(SHLIB_OPENMP_CXXFLAGS)"
-fi
-
-if test `uname -s` = "Darwin"
-then
-    OPENMP_CXXFLAGS='-Xclang -fopenmp'
-    OPENMP_LIB='-lomp'
-    ac_pkg_openmp=no
-    AC_MSG_CHECKING([whether OpenMP will work in a package])
-    AC_LANG(C)
-    AC_LANG_CONFTEST(
-        [
-            AC_LANG_PROGRAM(
-                [[
-                    #include <omp.h>
-                ]],
-                [[
-                    return (omp_get_max_threads() <= 1);
-                ]]
-            )
-        ]
-    )
-    ${CC} -o conftest conftest.c ${OPENMP_LIB} ${OPENMP_CXXFLAGS} 2>/dev/null && ./conftest && ac_pkg_openmp=yes
-    AC_MSG_RESULT([${ac_pkg_openmp}])
-    if test "${ac_pkg_openmp}" = no; then
-        OPENMP_CXXFLAGS=''
-        OPENMP_LIB=''
-        echo '***********************************************************************************************'
-        echo ' OpenMP is unavailable on this macOS system. LightGBM code will run single-threaded as a result.'
-        echo ' To use all CPU cores for training jobs, you should install OpenMP by running'
-        echo ''
-        echo '     brew install libomp'
-        echo '***********************************************************************************************'
-    fi
-fi
-
-# substitute variables from this script into Makevars.in
-AC_SUBST(OPENMP_CXXFLAGS)
-AC_SUBST(OPENMP_LIB)
-AC_SUBST(LGB_CPPFLAGS)
-AC_CONFIG_FILES([src/Makevars])
-
-# write out Autoconf output
-AC_OUTPUT
diff --git a/R-package/configure.win b/R-package/configure.win
deleted file mode 100755
index b6f95aacc..000000000
--- a/R-package/configure.win
+++ /dev/null
@@ -1,69 +0,0 @@
-# Script used to generate `Makevars.win` from `Makevars.win.in`
-# on Windows
-
-###########################
-# find compiler and flags #
-###########################
-
-R_SCRIPT="${R_HOME}/bin${R_ARCH_BIN}/Rscript"
-R_EXE="${R_HOME}/bin${R_ARCH_BIN}/R"
-CC=`"${R_EXE}" CMD config CC`
-
-# LightGBM-specific flags
-LGB_CPPFLAGS=""
-
-#########
-# Eigen #
-#########
-
-LGB_CPPFLAGS="${LGB_CPPFLAGS} -DEIGEN_MPL2_ONLY"
-
-###############
-# MM_PREFETCH #
-###############
-
-ac_mm_prefetch="no"
-
-cat > conftest.c <<EOL
-#include <xmmintrin.h>
-int main() {
-  int a = 0;
-  _mm_prefetch(&a, _MM_HINT_NTA);
-  return 0;
-}
-EOL
-
-${CC} -o conftest conftest.c 2>/dev/null && ./conftest && ac_mm_prefetch="yes"
-echo "checking whether MM_PREFETCH works...${ac_mm_prefetch}"
-
-if test "${ac_mm_prefetch}" = "yes";
-then
-    LGB_CPPFLAGS="${LGB_CPPFLAGS} -DMM_PREFETCH=1"
-fi
-
-############
-# MM_ALLOC #
-############
-ac_mm_malloc="no"
-
-cat > conftest.c <<EOL
-#include <mm_malloc.h>
-int main() {
-    char *a = (char*)_mm_malloc(8, 16);
-    _mm_free(a);
-    return 0;
-}
-EOL
-
-${CC} -o conftest conftest.c 2>/dev/null && ./conftest && ac_mm_malloc="yes"
-echo "checking whether MM_MALLOC works...${ac_mm_malloc}"
-
-if test "${ac_mm_malloc}" = "yes";
-then
-    LGB_CPPFLAGS="${LGB_CPPFLAGS} -DMM_MALLOC=1"
-fi
-
-# Generate Makevars.win from Makevars.win.in
-sed -e \
-    "s/@LGB_CPPFLAGS@/$LGB_CPPFLAGS/" \
-    < src/Makevars.win.in > src/Makevars.win
diff --git a/R-package/cran-comments.md b/R-package/cran-comments.md
deleted file mode 100644
index edfe7ed33..000000000
--- a/R-package/cran-comments.md
+++ /dev/null
@@ -1,545 +0,0 @@
-# CRAN Submission History
-
-## v3.2.1 - Submission 1 - (TBD)
-
-### CRAN response
-
-### Maintainer Notes
-
-## v3.2.0 - Submission 1 - (March 22, 2021)
-
-### CRAN response
-
-Package is failing checks in the `r-devel-linux-x86_64-debian-clang` environment (described [here](https://cran.r-project.org/web/checks/check_flavors.html#r-devel-linux-x86_64-debian-clang)). Specifically, one unit test on the use of non-ASCII feature names in `Booster$dump_model()` fails.
-
-> Apparently your package fails its checks in a strict Latin-1* locale,
-e.g. under Linux using LANG=en_US.iso88591 (see the debian-clang
-results).
-
-> Please correct before 2021-04-21 to safely retain your package on CRAN.
-
-### Maintainer Notes
-
-Submitted a version 3.2.1 to correct the errors noted.
-
-## v3.1.1 - Submission 1 - (December 7, 2020)
-
-### CRAN response
-
-Accepted to CRAN, December 8.
-
-### Maintainer Notes
-
-Submitted a fix to 3.1.0 that skips some learning-to-rank tests on 32-bit Windows.
-
-## v3.1.0 - Submission 1 - (November 15, 2020)
-
-### CRAN response
-
-Accepted to CRAN, November 18.
-
-On November 21, found out that the CRAN's `r-oldrel-windows-ix86+x86_64` check was failing, with an issue similar to the one faced on Solaris and fixed in https://github.com/microsoft/LightGBM/pull/3534.
-
-CRAN did not ask for a re-submission, but this was fixed in 3.1.1.
-
-### Maintainer Notes
-
-This package was submitted with the following information in the "optional comments" box.
-
-```text
-Hello,
-
-I'm submitting {lightgbm} 3.1.0 on behalf of the maintainer, Guolin Ke. I am a co-author on the package, and he has asked me to handle this submission. We saw in https://cran.r-project.org/web/packages/policies.html#Submission that this is permitted.
-
-{lightgbm} was removed from CRAN in October for issues found by valgrind checks. We have invested significant effort in addressing those issues and creating an automatic test that tries to replicate CRAN's valgrind checks: https://github.com/microsoft/LightGBM/blob/742d72f8bb051105484fd5cca11620493ffb0b2b/.github/workflows/r_valgrind.yml.
-
-We see two warnings from valgrind that we believe are not problematic.
-
-==2063== Conditional jump or move depends on uninitialised value(s)
-==2063==    at 0x49CF138: gregexpr_Regexc (grep.c:2439)
-==2063==    by 0x49D1F13: do_regexpr (grep.c:3100)
-==2063==    by 0x49A0058: bcEval (eval.c:7121)
-==2063==    by 0x498B67F: Rf_eval (eval.c:727)
-==2063==    by 0x498E414: R_execClosure (eval.c:1895)
-==2063==    by 0x498E0C7: Rf_applyClosure (eval.c:1821)
-==2063==    by 0x499FC8C: bcEval (eval.c:7089)
-==2063==    by 0x498B67F: Rf_eval (eval.c:727)
-==2063==    by 0x498B1CB: forcePromise (eval.c:555)
-==2063==    by 0x49963AB: FORCE_PROMISE (eval.c:5142)
-==2063==    by 0x4996566: getvar (eval.c:5183)
-==2063==    by 0x499D1A5: bcEval (eval.c:6873)
-==2063==  Uninitialised value was created by a stack allocation
-==2063==    at 0x49CEC37: gregexpr_Regexc (grep.c:2369)
-
-This seems to be related to R itself and not any code in {lightgbm}.
-
-==2063== 336 bytes in 1 blocks are possibly lost in loss record 153 of 2,709
-==2063==    at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
-==2063==    by 0x40149CA: allocate_dtv (dl-tls.c:286)
-==2063==    by 0x40149CA: _dl_allocate_tls (dl-tls.c:532)
-==2063==    by 0x5702322: allocate_stack (allocatestack.c:622)
-==2063==    by 0x5702322: pthread_create@@GLIBC_2.2.5 (pthread_create.c:660)
-==2063==    by 0x56D0DDA: ??? (in /usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0)
-==2063==    by 0x56C88E0: GOMP_parallel (in /usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0)
-==2063==    by 0x1544D29C: LGBM_DatasetCreateFromCSC (c_api.cpp:1286)
-==2063==    by 0x1546F980: LGBM_DatasetCreateFromCSC_R (lightgbm_R.cpp:91)
-==2063==    by 0x4941E2F: R_doDotCall (dotcode.c:634)
-==2063==    by 0x494CCC6: do_dotcall (dotcode.c:1281)
-==2063==    by 0x499FB01: bcEval (eval.c:7078)
-==2063==    by 0x498B67F: Rf_eval (eval.c:727)
-==2063==    by 0x498E414: R_execClosure (eval.c:1895)
-
-We believe this is a false positive, and related to a misunderstanding between valgrind and openmp (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36298).
-
-We have also added automated tests with ASAN/UBSAN to our testing setup, and have checked the package on Solaris 10 and found no issues.
-
-Thanks for your time and consideration.
-```
-
-## v3.0.0.2 - Submission 1 - (September 29, 2020)
-
-### CRAN response
-
-First response was a message talking about failing checks on 3.0.0.
-
-```text
-package lightgbm_3.0.0.2.tar.gz has been auto-processed.
-The auto-check found additional issues for the last version released on CRAN:
-gcc-UBSAN <link>
-valgrind <link>
-CRAN incoming checks do not test for these additional issues and you will need an appropriately instrumented build of R to reproduce these.
-Hence please reply-all and explain: Have these been fixed?
-
-Please correct before 2020-10-05 to safely retain your package on CRAN.
-
-There is still a valgrind error. This did not happen when tested on
-submission, but the tests did run until timeout at 4 hours. When you
-write illegally, corruption is common.
-
-Illegal writes are serious errors.
-```
-
-Then in later responses to email correspondence with CRAN, CRAN expressed frustration with the number of failed submission and banned this package from new submissions for a month.
-
-The content of that frustrated message was regrettable and it does not need to be preserved forever in this file.
-
-### Maintainer Notes
-
-The 3.0.0.x series is officially not making it to CRAN. We will wait until November, and try again.
-
-Detailed plan about what will be tried before November 2020 to increase the likelihood of success for that package: https://github.com/microsoft/LightGBM/pull/3338#issuecomment-702756840.
-
-## v3.0.0.1 - Submission 1 - (September 24, 2020)
-
-### CRAN response
-
-```text
-Thanks, we see:
-
-Still lots of alignment errors, such as
-
-lightgbm.Rcheck/tests/testthat.Rout:io/dataset_loader.cpp:340:59:
-runtime error: reference binding to misaligned address 0x7f51fefad81e for type 'const value_type', which requires 4 byte alignment
-lightgbm.Rcheck/tests/testthat.Rout:/usr/include/c++/10/bits/stl_vector.h:1198:21:
-runtime error: reference binding to misaligned address 0x7f51fefad81e for type 'const int', which requires 4 byte alignment lightgbm.Rcheck/tests/testthat.Rout:/usr/include/c++/10/bits/vector.tcc:449:28:runtime
-error: reference binding to misaligned address 0x7f51fefad81e for type 'const type', which requires 4 byte alignment
-lightgbm.Rcheck/tests/testthat.Rout:/usr/include/c++/10/bits/move.h:77:36:
-runtime error: reference binding to misaligned address 0x7f51fefad81e for type 'const int', which requires 4 byte alignment
-lightgbm.Rcheck/tests/testthat.Rout:/usr/include/c++/10/bits/alloc_traits.h:512:17:
-runtime error: reference binding to misaligned address 0x7f51fefad81e for type 'const type', which requires 4 byte alignment
-
-Please fix and resubmit.
-```
-
-### Maintainer Notes
-
-Ok, these are the notes from the UBSAN tests. Was able to reproduce them with https://github.com/microsoft/LightGBM/pull/3338#issuecomment-700399862, and they were fixed in https://github.com/microsoft/LightGBM/pull/3415.
-
-Struggling to replicate the valgrind result (running `R CMD check --use-valgrind` returns no issues), so trying submission again. Hoping that the fixes for mis-alignment fix the other errors too.
-
-## v3.0.0 - Submission 6 - (September 24, 2020)
-
-### CRAN response
-
-Failing pre-checks.
-
-### `R CMD check` results
-
-```text
-* checking CRAN incoming feasibility ... WARNING
-Maintainer: ‘Guolin Ke <guolin.ke@microsoft.com>’
-
-Insufficient package version (submitted: 3.0.0, existing: 3.0.0)
-
-Days since last update: 4
-```
-
-### Maintainer Notes
-
-Did not think the version needed to be incremented if submitting a package in response to CRAN saying "you are failing checks and will be kicked off if you don't fix it", but I guess you do!
-
-This can be fixed by just re-submitting but with the version changed from `3.0.0` to `3.0.0.1`.
-
-## v3.0.0 - Submission 5 - (September 11, 2020)
-
-### CRAN Response
-
-Accepted to CRAN!
-
-Please correct the problems below before 2020-10-05 to safely retain your package on CRAN:
-
-```text
-checking installed package size ... NOTE
-  installed size is 49.7Mb
-  sub-directories of 1Mb or more:
-    libs 49.1Mb
-
-"network/socket_wrapper.hpp", line 30: Error: Could not open include file<ifaddrs.h>.
-"network/socket_wrapper.hpp", line 216: Error: The type "ifaddrs" is incomplete.
-"network/socket_wrapper.hpp", line 217: Error: The type "ifaddrs" is incomplete.
-"network/socket_wrapper.hpp", line 220: Error: The type "ifaddrs" is incomplete.
-"network/socket_wrapper.hpp", line 222: Error: The type "ifaddrs" is incomplete.
-"network/socket_wrapper.hpp", line 214: Error: The function "getifaddrs" must have a prototype.
-"network/socket_wrapper.hpp", line 228: Error: The function "freeifaddrs" must have a prototype.
-"network/linkers_socket.cpp", line 76: Warning: A non-POD object of type "std::chrono::duration<double, std::ratio<1, 1000>>" passed as a variable argument to function "static LightGBM::Log::Info(const char*, ...)".
-7 Error(s) and 1 Warning(s) detected.
-*** Error code 2
-make: Fatal error: Command failed for target `network/linkers_socket.o'
-Current working directory /tmp/RtmpNfaavG/R.INSTALL40a84f70130a/lightgbm/src
-ERROR: compilation failed for package ‘lightgbm’
-* removing ‘/home/ripley/R/Lib32/lightgbm’
-```
-
-### Maintainer Notes
-
-Added a patch that `psutil` has used to fix missing `ifaddrs.h` on Solaris 10: https://github.com/microsoft/LightGBM/issues/629#issuecomment-665091451.
-
-## v3.0.0 - Submission 4 - (September 4, 2020)
-
-### CRAN Response
-
-> Thanks, if the running time is the only reason to wrap the examples in
-\donttest, please replace \donttest by \donttest (\donttest examples are
-not executed in the CRAN checks).
-
-> Please replace cat() by message() or warning() in your functions (except
-for print() and summary() functions). Messages and warnings can be
-suppressed if needed.
-
-> Missing Rd-tags:
-  lightgbm/man/dimnames.lgb.Dataset.Rd: \value
-  lightgbm/man/lgb.Dataset.construct.Rd: \value
-  lightgbm/man/lgb.prepare.Rd: \value
-  ...
-
-> Please add the tag and explain in detail the returned objects.
-
-### Maintainer Notes
-
-Responded to CRAN with the following:
-
-All examples have been wrapped with `\donttest` as requested. We have replied to Swetlana Herbrandt asking for clarification on the donttest news item in the R 4.0.2 changelog (https://cran.r-project.org/doc/manuals/r-devel/NEWS.html).
-
-All uses of `cat()` have been replaced with `print()`. We chose `print()` over `message()` because it's important that they be written to stdout alongside all the other logs coming from the library's C++ code. `message()` and `warning()` write to stderr.
-
-All exported objects now have `\value{}` statements in their documentation files in `man/`.
-
-**We also replied directly to CRAN's feedback email**
-
-> Swetlana,
-
-> Thank you for your comments. I've just created a new submission that I believe addresses them.
-
-> Can you help us understand something? In your message you said "\donttest examples are
-not executed in the CRAN checks)", but in https://cran.r-project.org/doc/manuals/r-devel/NEWS.html  we see the following:
-
-> > "`R CMD check --as-cran` now runs \donttest examples (which are run by example()) instead of instructing the tester to do so. This can be temporarily circumvented during development by setting environment variable `_R_CHECK_DONTTEST_EXAMPLES_` to a false value."
-
-> Could you help us understand how both of those statements can be true?
-
-## v3.0.0 - Submission 3 - (August 29, 2020)
-
-### CRAN response
-
-* Please write references in the description of the DESCRIPTION file in
-the form
-  - authors (year) doi:...
-  - authors (year) arXiv:...
-  - authors (year, ISBN:...)
-* if those are not available: authors (year) https:... with no space after 'doi:', 'arXiv:', 'https:' and angle brackets for auto-linking.
-* (If you want to add a title as well please put it in quotes: "Title")
-
-* \donttest{} should only be used if the example really cannot be executed (e.g. because of missing additional software, missing API keys, ...) by the user. That's why wrapping examples in \donttest{} adds the comment ("# Not run:") as a warning for the user. Does not seem necessary. Please unwrap the examples if they are executable in < 5 sec, or replace
-\donttest{} with \donttest{}.
-
-* Please do not modify the global environment (e.g. by using <<-) in your
-functions. This is not allowed by the CRAN policies.
-
-* Please always add all authors, contributors and copyright holders in the Authors@R field with the appropriate roles. From CRAN policies you agreed to: "The ownership of copyright and intellectual property rights of all components of the package must be clear and unambiguous (including from the authors specification in the DESCRIPTION file). Where code is copied (or derived) from the work of others (including from R itself), care must be taken that any copyright/license statements are preserved and authorship is not misrepresented." e.g.: Microsoft Corporation, Dropbox Inc. Please explain in the submission comments what you did about this issue.
-
-Please fix and resubmit
-
-### Maintainer Notes
-
-Responded to CRAN with the following:
-
-The paper citation has been adjusted as requested. We were using 'glmnet' as a  guide on how to include the URL but maybe they are no longer in compliance with CRAN policies: https://github.com/cran/glmnet/blob/b1a4b50de01e0cd24343959d7cf86452bac17b26/DESCRIPTION
-
-All authors from the original LightGBM paper have been added to Authors@R as `"aut"`. We have also added Microsoft and DropBox, Inc. as `"cph"` (copyright holders). These roles were chosen based on the guidance in https://journal.r-project.org/archive/2012-1/RJournal_2012-1_Hornik~et~al.pdf.
-
-lightgbm's code does use `<<-`, but it does not modify the global environment. The uses of `<<-` in R/lgb.interprete.R and R/callback.R are in functions which are called in an environment created by the lightgbm functions that call them, and this operator is used to reach one level up into the calling function's environment.
-
-We chose to wrap our examples in `\donttest{}` because we found, through testing on https://builder.r-hub.io/ and in our own continuous integration environments, that their run time varies a lot between platforms, and we cannot guarantee that all examples will run in under 5 seconds. We intentionally chose `\donttest{}` over `\donttest{}` because this item in the R 4.0.0 changelog (https://cran.r-project.org/doc/manuals/r-devel/NEWS.html) seems to indicate that \donttest will be ignored by CRAN's automated checks:
-
-> "`R CMD check --as-cran` now runs \donttest examples (which are run by example()) instead of instructing the tester to do so. This can be temporarily circumvented during development by setting environment variable `_R_CHECK_DONTTEST_EXAMPLES_` to a false value."
-
-We run all examples with `R CMD check --as-cran --run-dontrun` in our continuous integration tests on every commit to the package, so we have high confidence that they are working correctly.
-
-## v3.0.0 - Submission 2 - (August 28, 2020)
-
-### CRAN response
-
-Failing pre-checks.
-
-### `R CMD check` results
-
-* Debian: 2 NOTEs
-
-    ```text
-    * checking CRAN incoming feasibility ... NOTE
-    Maintainer: 'Guolin Ke <guolin.ke@microsoft.com>'
-
-    New submission
-
-    Possibly mis-spelled words in DESCRIPTION:
-      Guolin (13:52)
-      Ke (13:48)
-      LightGBM (14:20)
-      al (13:62)
-      et (13:59)
-
-    * checking top-level files ... NOTE
-    Non-standard files/directories found at top level:
-      'docs' 'lightgbm-hex-logo.png' 'lightgbm-hex-logo.svg'
-    ```
-
-* Windows: 2 NOTEs
-
-    ```text
-    * checking CRAN incoming feasibility ... NOTE
-    Maintainer: 'Guolin Ke <guolin.ke@microsoft.com>'
-
-    New submission
-
-    Possibly mis-spelled words in DESCRIPTION:
-      Guolin (13:52)
-      Ke (13:48)
-      LightGBM (14:20)
-      al (13:62)
-      et (13:59)
-
-    * checking top-level files ... NOTE
-    Non-standard files/directories found at top level:
-      'docs' 'lightgbm-hex-logo.png' 'lightgbm-hex-logo.svg'
-    ```
-
-### Maintainer Notes
-
-We should tell them the misspellings note is a false positive.
-
-For the note about included files, that is my fault. I had extra files laying around when I generated the package. I'm surprised to see `docs/` in that list, since it is ignored in  `.Rbuildignore`. I even tested that with [the exact code Rbuildignore uses](https://github.com/wch/r-source/blob/9d13622f41cfa0f36db2595bd6a5bf93e2010e21/src/library/tools/R/build.R#L85). For now, I added `rm -r  docs/` to `build-cran-package.sh`. We can figure out what is happening with `.Rbuildignore` in the future, but it shouldn't block a release.
-
-## v3.0.0 - Submission 1 - (August 24, 2020)
-
-NOTE: 3.0.0-1 was never released to CRAN. CRAN was on vacation August 14-24, 2020, and in that time version 3.0.0-1 (a release candidate) became 3.0.0.
-
-### CRAN response
-
-> Please only ship the CRAN template for the MIT license.
-
-> Is there some reference about the method you can add in the Description field in the form Authors (year) doi:.....?
-
-> Please fix and resubmit.
-
-### `R CMD check` results
-
-* Debian: 1 NOTE
-
-    ```text
-    * checking CRAN incoming feasibility ... NOTE
-    Maintainer: ‘Guolin Ke <guolin.ke@microsoft.com>’
-
-    New submission
-
-    License components with restrictions and base license permitting such:
-      MIT + file LICENSE
-    ```
-
-* Windows: 1 NOTE
-
-    ```text
-    * checking CRAN incoming feasibility ... NOTE
-    Maintainer: 'Guolin Ke <guolin.ke@microsoft.com>'
-
-    New submission
-
-    License components with restrictions and base license permitting such:
-      MIT + file LICENSE
-    ```
-
-### Maintainer Notes
-
-Tried updating `LICENSE` file to this template:
-
-```yaml
-YEAR: 2016
-COPYRIGHT HOLDER: Microsoft Corporation
-```
-
-Added a citation and link for [the main paper](https://papers.nips.cc/paper/6907-lightgbm-a-highly-efficient-gradient-boosting-decision) in `DESCRIPTION`.
-
-## v3.0.0-1 - Submission 3 - (August 12, 2020)
-
-### CRAN response
-
-Failing pre-checks.
-
-### `R CMD check` results
-
-* Debian: 1 NOTE
-
-    ```text
-    * checking CRAN incoming feasibility ... NOTE
-    Maintainer: ‘Guolin Ke <guolin.ke@microsoft.com>’
-
-    New submission
-
-    License components with restrictions and base license permitting such:
-      MIT + file LICENSE
-    ```
-
-* Windows: 1 ERROR, 1 NOTE
-
-    ```text
-    * checking CRAN incoming feasibility ... NOTE
-    Maintainer: ‘Guolin Ke <guolin.ke@microsoft.com>’
-
-    New submission
-
-    License components with restrictions and base license permitting such:
-      MIT + file LICENSE
-
-    ** running tests for arch 'i386' ... [9s] ERROR
-      Running 'testthat.R' [8s]
-    Running the tests in 'tests/testthat.R' failed.
-    Complete output:
-      > library(testthat)
-      > library(lightgbm)
-      Loading required package: R6
-      >
-      > test_check(
-      +     package = "lightgbm"
-      +     , stop_on_failure = TRUE
-      +     , stop_on_warning = FALSE
-      + )
-      -- 1. Error: predictions do not fail for integer input (@test_Predictor.R#7)  --
-      lgb.Dataset.construct: cannot create Dataset handle
-      Backtrace:
-       1. lightgbm::lgb.train(...)
-       2. data$construct()
-    ```
-
-### Maintainer Notes
-
-The "checking CRAN incoming feasibility" NOTE can be safely ignored. It only shows up the first time you submit a package to CRAN.
-
-So the only thing I see broken right now is the test error on 32-bit Windows. This is documented in https://github.com/microsoft/LightGBM/issues/3187.
-
-## v3.0.0-1 - Submission 2 - (August 10, 2020)
-
-### CRAN response
-
-Failing pre-checks.
-
-### `R CMD check` results
-
-* Debian: 2 NOTEs
-
-    ```text
-    * checking CRAN incoming feasibility ... NOTE
-    Maintainer: ‘Guolin Ke <guolin.ke@microsoft.com>’
-
-    New submission
-
-    License components with restrictions and base license permitting such:
-      MIT + file LICENSE
-
-    Non-standard files/directories found at top level:
-    ‘cran-comments.md’ ‘docs’
-    ```
-
-* Windows: 1 ERROR, 2 NOTEs
-
-    ```text
-    * checking CRAN incoming feasibility ... NOTE
-    Maintainer: 'Guolin Ke <guolin.ke@microsoft.com>'
-
-    New submission
-
-    License components with restrictions and base license permitting such:
-      MIT + file LICENSE
-
-    * checking top-level files ... NOTE
-    Non-standard files/directories found at top level:
-      'cran-comments.md' 'docs'
-
-    ** checking whether the package can be loaded ... ERROR
-    Loading this package had a fatal error status code 1
-    Loading log:
-    Error: package 'lightgbm' is not installed for 'arch = i386'
-    Execution halted
-    ```
-
-### Maintainer Notes
-
-Seems removing `Biarch` field didn't work. Noticed this in the install logs:
-
-> Warning: this package has a non-empty 'configure.win' file, so building only the main architecture
-
-Tried adding `Biarch: true` to `DESCRIPTION` to overcome this.
-
-NOTE about non-standard files was the result of a mistake in `.Rbuildignore` syntax, and something strange with how `cran-comments.md` line in `.Rbuildignore`  was treated. Updated `.Rbuildignore` and added an `rm cran-comments.md` to `build-cran-package.sh`.
-
-## v3.0.0-1 - Submission 1 - (August 9, 2020)
-
-### CRAN response
-
-Failing pre-checks.
-
-### `R CMD check` results
-
-* Debian: 1 NOTE
-
-    ```text
-    Possibly mis-spelled words in DESCRIPTION:
-      LightGBM (12:88, 19:41, 20:60, 20:264)
-    ```
-
-* Windows: 1 ERROR, 1 NOTE
-
-    ```text
-    Possibly mis-spelled words in DESCRIPTION:
-      LightGBM (12:88, 19:41, 20:60, 20:264)
-
-    ** checking whether the package can be loaded ... ERROR
-    Loading this package had a fatal error status code 1
-    Loading log:
-    Error: package 'lightgbm' is not installed for 'arch = i386'
-    Execution halted
-    ```
-
-### Maintainer Notes
-
-Thought the issue on Windows was caused by `Biarch: false` in `DESCRIPTION`. Removed `Biarch` field.
-
-Thought the "misspellings" issue could be resolved by adding single quotes around LightGBM, like `'LightGBM'`.
diff --git a/R-package/data/agaricus.train.rda b/R-package/data/agaricus.train.rda
deleted file mode 100644
index 3f5f24144..000000000
Binary files a/R-package/data/agaricus.train.rda and /dev/null differ
diff --git a/R-package/data/bank.rda b/R-package/data/bank.rda
deleted file mode 100644
index 7e2058883..000000000
Binary files a/R-package/data/bank.rda and /dev/null differ
diff --git a/R-package/demo/00Index b/R-package/demo/00Index
deleted file mode 100644
index f5b614472..000000000
--- a/R-package/demo/00Index
+++ /dev/null
@@ -1,10 +0,0 @@
-basic_walkthrough               Basic feature walkthrough
-boost_from_prediction           Boosting from existing prediction
-categorical_features_rules       Categorical Feature Preparation with Rules
-cross_validation                Cross Validation
-early_stopping                  Early Stop in training
-efficient_many_training         Efficiency for Many Model Trainings
-multiclass                      Multiclass training/prediction
-multiclass_custom_objective     Multiclass with Custom Objective Function
-leaf_stability                  Leaf (in)Stability example
-weight_param                    Weight-Parameter adjustment relationship
diff --git a/R-package/demo/basic_walkthrough.R b/R-package/demo/basic_walkthrough.R
deleted file mode 100644
index 6716bb894..000000000
--- a/R-package/demo/basic_walkthrough.R
+++ /dev/null
@@ -1,169 +0,0 @@
-library(lightgbm)
-library(methods)
-
-# We load in the agaricus dataset
-# In this example, we are aiming to predict whether a mushroom is edible
-data(agaricus.train, package = "lightgbm")
-data(agaricus.test, package = "lightgbm")
-train <- agaricus.train
-test <- agaricus.test
-
-# The loaded data is stored in sparseMatrix, and label is a numeric vector in {0,1}
-class(train$label)
-class(train$data)
-
-#--------------------Basic Training using lightgbm----------------
-# This is the basic usage of lightgbm you can put matrix in data field
-# Note: we are putting in sparse matrix here, lightgbm naturally handles sparse input
-# Use sparse matrix when your feature is sparse (e.g. when you are using one-hot encoding vector)
-print("Training lightgbm with sparseMatrix")
-bst <- lightgbm(
-    data = train$data
-    , label = train$label
-    , num_leaves = 4L
-    , learning_rate = 1.0
-    , nrounds = 2L
-    , objective = "binary"
-)
-
-# Alternatively, you can put in dense matrix, i.e. basic R-matrix
-print("Training lightgbm with Matrix")
-bst <- lightgbm(
-    data = as.matrix(train$data)
-    , label = train$label
-    , num_leaves = 4L
-    , learning_rate = 1.0
-    , nrounds = 2L
-    , objective = "binary"
-)
-
-# You can also put in lgb.Dataset object, which stores label, data and other meta datas needed for advanced features
-print("Training lightgbm with lgb.Dataset")
-dtrain <- lgb.Dataset(
-    data = train$data
-    , label = train$label
-)
-bst <- lightgbm(
-    data = dtrain
-    , num_leaves = 4L
-    , learning_rate = 1.0
-    , nrounds = 2L
-    , objective = "binary"
-)
-
-# Verbose = 0,1,2
-print("Train lightgbm with verbose 0, no message")
-bst <- lightgbm(
-    data = dtrain
-    , num_leaves = 4L
-    , learning_rate = 1.0
-    , nrounds = 2L
-    , objective = "binary"
-    , verbose = 0L
-)
-
-print("Train lightgbm with verbose 1, print evaluation metric")
-bst <- lightgbm(
-    data = dtrain
-    , num_leaves = 4L
-    , learning_rate = 1.0
-    , nrounds = 2L
-    , nthread = 2L
-    , objective = "binary"
-    , verbose = 1L
-)
-
-print("Train lightgbm with verbose 2, also print information about tree")
-bst <- lightgbm(
-    data = dtrain
-    , num_leaves = 4L
-    , learning_rate = 1.0
-    , nrounds = 2L
-    , nthread = 2L
-    , objective = "binary"
-    , verbose = 2L
-)
-
-# You can also specify data as file path to a LibSVM/TCV/CSV format input
-# Since we do not have this file with us, the following line is just for illustration
-# bst <- lightgbm(
-#     data = "agaricus.train.svm"
-#     , num_leaves = 4L
-#     , learning_rate = 1.0
-#     , nrounds = 2L
-#     , objective = "binary"
-# )
-
-#--------------------Basic prediction using lightgbm--------------
-# You can do prediction using the following line
-# You can put in Matrix, sparseMatrix, or lgb.Dataset
-pred <- predict(bst, test$data)
-err <- mean(as.numeric(pred > 0.5) != test$label)
-print(paste("test-error=", err))
-
-#--------------------Save and load models-------------------------
-# Save model to binary local file
-lgb.save(bst, "lightgbm.model")
-
-# Load binary model to R
-bst2 <- lgb.load("lightgbm.model")
-pred2 <- predict(bst2, test$data)
-
-# pred2 should be identical to pred
-print(paste("sum(abs(pred2-pred))=", sum(abs(pred2 - pred))))
-
-#--------------------Advanced features ---------------------------
-# To use advanced features, we need to put data in lgb.Dataset
-dtrain <- lgb.Dataset(data = train$data, label = train$label, free_raw_data = FALSE)
-dtest <- lgb.Dataset.create.valid(dtrain, data = test$data, label = test$label)
-
-#--------------------Using validation set-------------------------
-# valids is a list of lgb.Dataset, each of them is tagged with name
-valids <- list(train = dtrain, test = dtest)
-
-# To train with valids, use lgb.train, which contains more advanced features
-# valids allows us to monitor the evaluation result on all data in the list
-print("Train lightgbm using lgb.train with valids")
-bst <- lgb.train(
-    data = dtrain
-    , num_leaves = 4L
-    , learning_rate = 1.0
-    , nrounds = 2L
-    , valids = valids
-    , nthread = 2L
-    , objective = "binary"
-)
-
-# We can change evaluation metrics, or use multiple evaluation metrics
-print("Train lightgbm using lgb.train with valids, watch logloss and error")
-bst <- lgb.train(
-    data = dtrain
-    , num_leaves = 4L
-    , learning_rate = 1.0
-    , nrounds = 2L
-    , valids = valids
-    , eval = c("binary_error", "binary_logloss")
-    , nthread = 2L
-    , objective = "binary"
-)
-
-# lgb.Dataset can also be saved using lgb.Dataset.save
-lgb.Dataset.save(dtrain, "dtrain.buffer")
-
-# To load it in, simply call lgb.Dataset
-dtrain2 <- lgb.Dataset("dtrain.buffer")
-bst <- lgb.train(
-    data = dtrain2
-    , num_leaves = 4L
-    , learning_rate = 1.0
-    , nrounds = 2L
-    , valids = valids
-    , nthread = 2L
-    , objective = "binary"
-)
-
-# information can be extracted from lgb.Dataset using getinfo
-label <- getinfo(dtest, "label")
-pred <- predict(bst, test$data)
-err <- as.numeric(sum(as.integer(pred > 0.5) != label)) / length(label)
-print(paste("test-error=", err))
diff --git a/R-package/demo/boost_from_prediction.R b/R-package/demo/boost_from_prediction.R
deleted file mode 100644
index 457561cd5..000000000
--- a/R-package/demo/boost_from_prediction.R
+++ /dev/null
@@ -1,39 +0,0 @@
-library(lightgbm)
-library(methods)
-
-# Load in the agaricus dataset
-data(agaricus.train, package = "lightgbm")
-data(agaricus.test, package = "lightgbm")
-dtrain <- lgb.Dataset(agaricus.train$data, label = agaricus.train$label)
-dtest <- lgb.Dataset.create.valid(dtrain, data = agaricus.test$data, label = agaricus.test$label)
-
-valids <- list(eval = dtest, train = dtrain)
-#--------------------Advanced features ---------------------------
-# advanced: start from an initial base prediction
-print("Start running example to start from an initial prediction")
-
-# Train lightgbm for 1 round
-param <- list(
-    num_leaves = 4L
-    , learning_rate = 1.0
-    , nthread = 2L
-    , objective = "binary"
-)
-bst <- lgb.train(param, dtrain, 1L, valids = valids)
-
-# Note: we need the margin value instead of transformed prediction in set_init_score
-ptrain <- predict(bst, agaricus.train$data, rawscore = TRUE)
-ptest  <- predict(bst, agaricus.test$data, rawscore = TRUE)
-
-# set the init_score property of dtrain and dtest
-# base margin is the base prediction we will boost from
-setinfo(dtrain, "init_score", ptrain)
-setinfo(dtest, "init_score", ptest)
-
-print("This is result of boost from initial prediction")
-bst <- lgb.train(
-    params = param
-    , data = dtrain
-    , nrounds = 5L
-    , valids = valids
-)
diff --git a/R-package/demo/categorical_features_rules.R b/R-package/demo/categorical_features_rules.R
deleted file mode 100644
index 68df09f24..000000000
--- a/R-package/demo/categorical_features_rules.R
+++ /dev/null
@@ -1,101 +0,0 @@
-# Here we are going to try training a model with categorical features
-
-# Load libraries
-library(data.table)
-library(lightgbm)
-
-# Load data and look at the structure
-#
-# Classes 'data.table' and 'data.frame':	4521 obs. of  17 variables:
-# $ age      : int  30 33 35 30 59 35 36 39 41 43 ...
-# $ job      : chr  "unemployed" "services" "management" "management" ...
-# $ marital  : chr  "married" "married" "single" "married" ...
-# $ education: chr  "primary" "secondary" "tertiary" "tertiary" ...
-# $ default  : chr  "no" "no" "no" "no" ...
-# $ balance  : int  1787 4789 1350 1476 0 747 307 147 221 -88 ...
-# $ housing  : chr  "no" "yes" "yes" "yes" ...
-# $ loan     : chr  "no" "yes" "no" "yes" ...
-# $ contact  : chr  "cellular" "cellular" "cellular" "unknown" ...
-# $ day      : int  19 11 16 3 5 23 14 6 14 17 ...
-# $ month    : chr  "oct" "may" "apr" "jun" ...
-# $ duration : int  79 220 185 199 226 141 341 151 57 313 ...
-# $ campaign : int  1 1 1 4 1 2 1 2 2 1 ...
-# $ pdays    : int  -1 339 330 -1 -1 176 330 -1 -1 147 ...
-# $ previous : int  0 4 1 0 0 3 2 0 0 2 ...
-# $ poutcome : chr  "unknown" "failure" "failure" "unknown" ...
-# $ y        : chr  "no" "no" "no" "no" ...
-data(bank, package = "lightgbm")
-str(bank)
-
-# We are dividing the dataset into two: one train, one validation
-bank_train <- bank[1L:4000L, ]
-bank_test <- bank[4001L:4521L, ]
-
-# We must now transform the data to fit in LightGBM
-# For this task, we use lgb.convert_with_rules
-# The function transforms the data into a fittable data
-#
-# Classes 'data.table' and 'data.frame':	521 obs. of  17 variables:
-# $ age      : int  53 36 58 26 34 55 55 34 41 38 ...
-# $ job      : num  1 10 10 9 10 2 2 3 3 4 ...
-# $ marital  : num  1 2 1 3 3 2 2 2 1 1 ...
-# $ education: num  2 2 2 2 2 1 2 3 2 2 ...
-# $ default  : num  1 1 1 1 1 1 1 1 1 1 ...
-# $ balance  : int  26 191 -123 -147 179 1086 471 105 1588 70 ...
-# $ housing  : num  2 1 1 1 1 2 2 2 2 1 ...
-# $ loan     : num  1 1 1 1 1 1 1 1 2 1 ...
-# $ contact  : num  1 1 1 3 1 1 3 3 3 1 ...
-# $ day      : int  7 31 5 4 19 6 30 28 20 27 ...
-# $ month    : num  9 2 2 7 2 9 9 9 7 11 ...
-# $ duration : int  56 69 131 95 294 146 58 249 10 255 ...
-# $ campaign : int  1 1 2 2 3 1 2 2 8 3 ...
-# $ pdays    : int  359 -1 -1 -1 -1 272 -1 -1 -1 148 ...
-# $ previous : int  1 0 0 0 0 2 0 0 0 1 ...
-# $ poutcome : num  1 4 4 4 4 1 4 4 4 3 ...
-# $ y        : num  1 1 1 1 1 1 1 1 1 2 ...
-bank_rules <- lgb.convert_with_rules(data = bank_train)
-bank_train <- bank_rules$data
-bank_test <- lgb.convert_with_rules(data = bank_test, rules = bank_rules$rules)$data
-str(bank_test)
-
-# Remove 1 to label because it must be between 0 and 1
-bank_train$y <- bank_train$y - 1L
-bank_test$y <- bank_test$y - 1L
-
-# Data input to LightGBM must be a matrix, without the label
-my_data_train <- as.matrix(bank_train[, 1L:16L, with = FALSE])
-my_data_test <- as.matrix(bank_test[, 1L:16L, with = FALSE])
-
-# Creating the LightGBM dataset with categorical features
-# The categorical features can be passed to lgb.train to not copy and paste a lot
-dtrain <- lgb.Dataset(
-    data = my_data_train
-    , label = bank_train$y
-    , categorical_feature = c(2L, 3L, 4L, 5L, 7L, 8L, 9L, 11L, 16L)
-)
-dtest <- lgb.Dataset.create.valid(
-    dtrain
-    , data = my_data_test
-    , label = bank_test$y
-)
-
-# We can now train a model
-params <- list(
-    objective = "binary"
-    , metric = "l2"
-    , min_data = 1L
-    , learning_rate = 0.1
-    , min_data = 0L
-    , min_hessian = 1.0
-    , max_depth = 2L
-)
-model <- lgb.train(
-    params = params
-    , data = dtrain
-    , nrounds = 100L
-    , valids = list(train = dtrain, valid = dtest)
-)
-
-# Try to find split_feature: 11
-# If you find it, it means it used a categorical feature in the first tree
-lgb.dump(model, num_iteration = 1L)
diff --git a/R-package/demo/cross_validation.R b/R-package/demo/cross_validation.R
deleted file mode 100644
index f685b5208..000000000
--- a/R-package/demo/cross_validation.R
+++ /dev/null
@@ -1,72 +0,0 @@
-library(lightgbm)
-
-# load in the agaricus dataset
-data(agaricus.train, package = "lightgbm")
-data(agaricus.test, package = "lightgbm")
-dtrain <- lgb.Dataset(agaricus.train$data, label = agaricus.train$label)
-dtest <- lgb.Dataset.create.valid(dtrain, data = agaricus.test$data, label = agaricus.test$label)
-
-nrounds <- 2L
-param <- list(
-  num_leaves = 4L
-  , learning_rate = 1.0
-  , objective = "binary"
-)
-
-print("Running cross validation")
-# Do cross validation, this will print result out as
-# [iteration]  metric_name:mean_value+std_value
-# std_value is standard deviation of the metric
-lgb.cv(
-  param
-  , dtrain
-  , nrounds
-  , nfold = 5L
-  , eval = "binary_error"
-)
-
-print("Running cross validation, disable standard deviation display")
-# do cross validation, this will print result out as
-# [iteration]  metric_name:mean_value+std_value
-# std_value is standard deviation of the metric
-lgb.cv(
-  param
-  , dtrain
-  , nrounds
-  , nfold = 5L
-  , eval = "binary_error"
-  , showsd = FALSE
-)
-
-# You can also do cross validation with cutomized loss function
-print("Running cross validation, with cutomsized loss function")
-
-logregobj <- function(preds, dtrain) {
-  labels <- getinfo(dtrain, "label")
-  preds <- 1.0 / (1.0 + exp(-preds))
-  grad <- preds - labels
-  hess <- preds * (1.0 - preds)
-  return(list(grad = grad, hess = hess))
-}
-
-# User-defined evaluation function returns a pair (metric_name, result, higher_better)
-# NOTE: when you do customized loss function, the default prediction value is margin
-# This may make built-in evalution metric calculate wrong results
-# For example, we are doing logistic loss, the prediction is score before logistic transformation
-# Keep this in mind when you use the customization, and maybe you need write customized evaluation function
-evalerror <- function(preds, dtrain) {
-  labels <- getinfo(dtrain, "label")
-  preds <- 1.0 / (1.0 + exp(-preds))
-  err <- as.numeric(sum(labels != (preds > 0.5))) / length(labels)
-  return(list(name = "error", value = err, higher_better = FALSE))
-}
-
-# train with customized objective
-lgb.cv(
-  params = param
-  , data = dtrain
-  , nrounds = nrounds
-  , obj = logregobj
-  , eval = evalerror
-  , nfold = 5L
-)
diff --git a/R-package/demo/early_stopping.R b/R-package/demo/early_stopping.R
deleted file mode 100644
index f68b82dc3..000000000
--- a/R-package/demo/early_stopping.R
+++ /dev/null
@@ -1,52 +0,0 @@
-library(lightgbm)
-library(methods)
-
-# Load in the agaricus dataset
-data(agaricus.train, package = "lightgbm")
-data(agaricus.test, package = "lightgbm")
-
-dtrain <- lgb.Dataset(agaricus.train$data, label = agaricus.train$label)
-dtest <- lgb.Dataset.create.valid(dtrain, data = agaricus.test$data, label = agaricus.test$label)
-
-# Note: for customized objective function, we leave objective as default
-# Note: what we are getting is margin value in prediction
-# You must know what you are doing
-param <- list(
-  num_leaves = 4L
-  , learning_rate = 1.0
-)
-valids <- list(eval = dtest)
-num_round <- 20L
-
-# User define objective function, given prediction, return gradient and second order gradient
-# This is loglikelihood loss
-logregobj <- function(preds, dtrain) {
-  labels <- getinfo(dtrain, "label")
-  preds <- 1.0 / (1.0 + exp(-preds))
-  grad <- preds - labels
-  hess <- preds * (1.0 - preds)
-  return(list(grad = grad, hess = hess))
-}
-
-# User-defined evaluation function returns a pair (metric_name, result, higher_better)
-# NOTE: when you do customized loss function, the default prediction value is margin
-# This may make built-in evalution metric calculate wrong results
-# For example, we are doing logistic loss, the prediction is score before logistic transformation
-# The built-in evaluation error assumes input is after logistic transformation
-# Keep this in mind when you use the customization, and maybe you need write customized evaluation function
-evalerror <- function(preds, dtrain) {
-  labels <- getinfo(dtrain, "label")
-  err <- as.numeric(sum(labels != (preds > 0.5))) / length(labels)
-  return(list(name = "error", value = err, higher_better = FALSE))
-}
-print("Start training with early Stopping setting")
-
-bst <- lgb.train(
-  param
-  , dtrain
-  , num_round
-  , valids
-  , objective = logregobj
-  , eval = evalerror
-  , early_stopping_round = 3L
-)
diff --git a/R-package/demo/efficient_many_training.R b/R-package/demo/efficient_many_training.R
deleted file mode 100644
index c7a05d204..000000000
--- a/R-package/demo/efficient_many_training.R
+++ /dev/null
@@ -1,36 +0,0 @@
-# Efficient training means training without giving up too much RAM
-# In the case of many trainings (like 100+ models), RAM will be eaten very quickly
-# Therefore, it is essential to know a strategy to deal with such issue
-
-# More results can be found here: https://github.com/microsoft/LightGBM/issues/879#issuecomment-326656580
-# Quote: "@Laurae2 Thanks for nice easily reproducible example (unlike mine).
-# With reset=FALSE you get after 500 iterations (not 1000): OS reports 27GB usage, while R gc() reports 1.5GB.
-# Just doing reset=TRUE will already improve things: OS reports 4.6GB.
-# Doing reset=TRUE and calling gc() in the loop will have OS 1.3GB. Thanks for the latest tip."
-
-# Load library
-library(lightgbm)
-
-# Generate fictive data of size 1M x 100
-set.seed(11111L)
-x_data <- matrix(rnorm(n = 100000000L, mean = 0.0, sd = 100.0), nrow = 1000000L, ncol = 100L)
-y_data <- rnorm(n = 1000000L, mean = 0.0, sd = 5.0)
-
-# Create lgb.Dataset for training
-data <- lgb.Dataset(x_data, label = y_data)
-data$construct()
-
-# Loop through a training of 1000 models, please check your RAM on your task manager
-# It MUST remain constant (if not increasing very slightly)
-gbm <- list()
-
-for (i in 1L:1000L) {
-  print(i)
-  gbm[[i]] <- lgb.train(
-      params = list(objective = "regression")
-      , data = data
-      , 1L
-      , reset_data = TRUE
-  )
-  gc(verbose = FALSE)
-}
diff --git a/R-package/demo/leaf_stability.R b/R-package/demo/leaf_stability.R
deleted file mode 100644
index bad2e8310..000000000
--- a/R-package/demo/leaf_stability.R
+++ /dev/null
@@ -1,245 +0,0 @@
-# We are going to look at how iterating too much might generate observation instability.
-# Obviously, we are in a controlled environment, without issues (real rules).
-# Do not do this in a real scenario.
-
-library(lightgbm)
-
-# define helper functions for creating plots
-
-# output of `RColorBrewer::brewer.pal(10, "RdYlGn")`, hardcooded here to avoid a dependency
-.diverging_palette <- c(
-  "#A50026", "#D73027", "#F46D43", "#FDAE61", "#FEE08B"
-  , "#D9EF8B", "#A6D96A", "#66BD63", "#1A9850", "#006837"
-)
-
-.prediction_depth_plot <- function(df) {
-  plot(
-    x = df$X
-    , y = df$Y
-    , type = "p"
-    , main = "Prediction Depth"
-    , xlab = "Leaf Bin"
-    , ylab = "Prediction Probability"
-    , pch = 19L
-    , col = .diverging_palette[df$binned + 1L]
-  )
-  legend(
-    "topright"
-    , title = "bin"
-    , legend = sort(unique(df$binned))
-    , pch = 19L
-    , col = .diverging_palette[sort(unique(df$binned + 1L))]
-    , cex = 0.7
-  )
-}
-
-.prediction_depth_spread_plot <- function(df) {
-  plot(
-    x = df$binned
-    , xlim = c(0L, 9L)
-    , y = df$Z
-    , type = "p"
-    , main = "Prediction Depth Spread"
-    , xlab = "Leaf Bin"
-    , ylab = "Logloss"
-    , pch = 19L
-    , col = .diverging_palette[df$binned + 1L]
-  )
-  legend(
-    "topright"
-    , title = "bin"
-    , legend = sort(unique(df$binned))
-    , pch = 19L
-    , col = .diverging_palette[sort(unique(df$binned + 1L))]
-    , cex = 0.7
-  )
-}
-
-.depth_density_plot <- function(df) {
-  plot(
-    x = density(df$Y)
-    , xlim = c(min(df$Y), max(df$Y))
-    , type = "p"
-    , main = "Depth Density"
-    , xlab = "Prediction Probability"
-    , ylab = "Bin Density"
-    , pch = 19L
-    , col = .diverging_palette[df$binned + 1L]
-  )
-  legend(
-    "topright"
-    , title = "bin"
-    , legend = sort(unique(df$binned))
-    , pch = 19L
-    , col = .diverging_palette[sort(unique(df$binned + 1L))]
-    , cex = 0.7
-  )
-}
-
-# load some data
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-
-# setup parameters and we train a model
-params <- list(objective = "regression", metric = "l2")
-valids <- list(test = dtest)
-model <- lgb.train(
-    params
-    , dtrain
-    , 50L
-    , valids
-    , min_data = 1L
-    , learning_rate = 0.1
-    , bagging_fraction = 0.1
-    , bagging_freq = 1L
-    , bagging_seed = 1L
-)
-
-# We create a data.frame with the following structure:
-# X = average leaf of the observation throughout all trees
-# Y = prediction probability (clamped to [1e-15, 1-1e-15])
-# Z = logloss
-# binned = binned quantile of average leaf
-new_data <- data.frame(
-    X = rowMeans(predict(
-        model
-        , agaricus.test$data
-        , predleaf = TRUE
-    ))
-    , Y = pmin(
-        pmax(
-            predict(model, agaricus.test$data)
-            , 1e-15
-        )
-        , 1.0 - 1e-15
-    )
-)
-new_data$Z <- -1.0 * (agaricus.test$label * log(new_data$Y) + (1L - agaricus.test$label) * log(1L - new_data$Y))
-new_data$binned <- .bincode(
-    x = new_data$X
-    , breaks = quantile(
-        x = new_data$X
-        , probs = seq_len(9L) / 10.0
-    )
-    , right = TRUE
-    , include.lowest = TRUE
-)
-new_data$binned[is.na(new_data$binned)] <- 0L
-
-# We can check the binned content
-table(new_data$binned)
-
-# We can plot the binned content
-# On the second plot, we clearly notice the lower the bin (the lower the leaf value), the higher the loss
-# On the third plot, it is smooth!
-.prediction_depth_plot(df = new_data)
-.prediction_depth_spread_plot(df = new_data)
-.depth_density_plot(df = new_data)
-
-# Now, let's show with other parameters
-model2 <- lgb.train(
-    params
-    , dtrain
-    , 100L
-    , valids
-    , min_data = 1L
-    , learning_rate = 1.0
-)
-
-# We create the data structure, but for model2
-new_data2 <- data.frame(
-    X = rowMeans(predict(
-        model2
-        , agaricus.test$data
-        , predleaf = TRUE
-    ))
-    , Y = pmin(
-        pmax(
-            predict(
-                model2
-                , agaricus.test$data
-            )
-            , 1e-15
-        )
-      , 1.0 - 1e-15
-     )
-)
-new_data2$Z <- -1.0 * (agaricus.test$label * log(new_data2$Y) + (1L - agaricus.test$label) * log(1L - new_data2$Y))
-new_data2$binned <- .bincode(
-    x = new_data2$X
-    , breaks = quantile(
-        x = new_data2$X
-        , probs = seq_len(9L) / 10.0
-    )
-    , right = TRUE
-    , include.lowest = TRUE
-)
-new_data2$binned[is.na(new_data2$binned)] <- 0L
-
-# We can check the binned content
-table(new_data2$binned)
-
-# We can plot the binned content
-# On the second plot, we clearly notice the lower the bin (the lower the leaf value), the higher the loss
-# On the third plot, it is clearly not smooth! We are severely overfitting the data, but the rules are
-# real thus it is not an issue
-# However, if the rules were not true, the loss would explode.
-.prediction_depth_plot(df = new_data2)
-.prediction_depth_spread_plot(df = new_data2)
-.depth_density_plot(df = new_data2)
-
-# Now, try with very severe overfitting
-model3 <- lgb.train(
-    params
-    , dtrain
-    , 1000L
-    , valids
-    , min_data = 1L
-    , learning_rate = 1.0
-)
-
-# We create the data structure, but for model3
-new_data3 <- data.frame(
-    X = rowMeans(predict(
-        model3
-        , agaricus.test$data
-        , predleaf = TRUE
-    ))
-    , Y = pmin(
-        pmax(
-            predict(
-                model3
-                , agaricus.test$data
-            )
-            , 1e-15
-        )
-        , 1.0 - 1e-15
-    )
-)
-new_data3$Z <- -1.0 * (agaricus.test$label * log(new_data3$Y) + (1L - agaricus.test$label) * log(1L - new_data3$Y))
-new_data3$binned <- .bincode(
-    x = new_data3$X
-    , breaks = quantile(
-        x = new_data3$X
-        , probs = seq_len(9L) / 10.0
-    )
-    , right = TRUE
-    , include.lowest = TRUE
-)
-new_data3$binned[is.na(new_data3$binned)] <- 0L
-
-# We can check the binned content
-table(new_data3$binned)
-
-# We can plot the binned content
-# On the third plot, it is clearly not smooth! We are severely overfitting the data, but the rules
-# are real thus it is not an issue.
-# However, if the rules were not true, the loss would explode. See the sudden spikes?
-.depth_density_plot(df = new_data3)
-
-# Compare with our second model, the difference is severe. This is smooth.
-.depth_density_plot(df = new_data2)
diff --git a/R-package/demo/multiclass.R b/R-package/demo/multiclass.R
deleted file mode 100644
index 00b49e83f..000000000
--- a/R-package/demo/multiclass.R
+++ /dev/null
@@ -1,70 +0,0 @@
-library(lightgbm)
-
-# We load the default iris dataset shipped with R
-data(iris)
-
-# We must convert factors to numeric
-# They must be starting from number 0 to use multiclass
-# For instance: 0, 1, 2, 3, 4, 5...
-iris$Species <- as.numeric(as.factor(iris$Species)) - 1L
-
-# We cut the data set into 80% train and 20% validation
-# The 10 last samples of each class are for validation
-
-train <- as.matrix(iris[c(1L:40L, 51L:90L, 101L:140L), ])
-test <- as.matrix(iris[c(41L:50L, 91L:100L, 141L:150L), ])
-dtrain <- lgb.Dataset(data = train[, 1L:4L], label = train[, 5L])
-dtest <- lgb.Dataset.create.valid(dtrain, data = test[, 1L:4L], label = test[, 5L])
-valids <- list(test = dtest)
-
-# Method 1 of training
-params <- list(objective = "multiclass", metric = "multi_error", num_class = 3L)
-model <- lgb.train(
-    params
-    , dtrain
-    , 100L
-    , valids
-    , min_data = 1L
-    , learning_rate = 1.0
-    , early_stopping_rounds = 10L
-)
-
-# We can predict on test data, outputs a 90-length vector
-# Order: obs1 class1, obs1 class2, obs1 class3, obs2 class1, obs2 class2, obs2 class3...
-my_preds <- predict(model, test[, 1L:4L])
-
-# Method 2 of training, identical
-model <- lgb.train(
-    list()
-    , dtrain
-    , 100L
-    , valids
-    , min_data = 1L
-    , learning_rate = 1.0
-    , early_stopping_rounds = 10L
-    , objective = "multiclass"
-    , metric = "multi_error"
-    , num_class = 3L
-)
-
-# We can predict on test data, identical
-my_preds <- predict(model, test[, 1L:4L])
-
-# A (30x3) matrix with the predictions, use parameter reshape
-# class1 class2 class3
-#   obs1   obs1   obs1
-#   obs2   obs2   obs2
-#   ....   ....   ....
-my_preds <- predict(model, test[, 1L:4L], reshape = TRUE)
-
-# We can also get the predicted scores before the Sigmoid/Softmax application
-my_preds <- predict(model, test[, 1L:4L], rawscore = TRUE)
-
-# Raw score predictions as matrix instead of vector
-my_preds <- predict(model, test[, 1L:4L], rawscore = TRUE, reshape = TRUE)
-
-# We can also get the leaf index
-my_preds <- predict(model, test[, 1L:4L], predleaf = TRUE)
-
-# Predict leaf index as matrix instead of vector
-my_preds <- predict(model, test[, 1L:4L], predleaf = TRUE, reshape = TRUE)
diff --git a/R-package/demo/multiclass_custom_objective.R b/R-package/demo/multiclass_custom_objective.R
deleted file mode 100644
index ec2ed90cd..000000000
--- a/R-package/demo/multiclass_custom_objective.R
+++ /dev/null
@@ -1,113 +0,0 @@
-library(lightgbm)
-
-# We load the default iris dataset shipped with R
-data(iris)
-
-# We must convert factors to numeric
-# They must be starting from number 0 to use multiclass
-# For instance: 0, 1, 2, 3, 4, 5...
-iris$Species <- as.numeric(as.factor(iris$Species)) - 1L
-
-# Create imbalanced training data (20, 30, 40 examples for classes 0, 1, 2)
-train <- as.matrix(iris[c(1L:20L, 51L:80L, 101L:140L), ])
-# The 10 last samples of each class are for validation
-test <- as.matrix(iris[c(41L:50L, 91L:100L, 141L:150L), ])
-
-dtrain <- lgb.Dataset(data = train[, 1L:4L], label = train[, 5L])
-dtest <- lgb.Dataset.create.valid(dtrain, data = test[, 1L:4L], label = test[, 5L])
-valids <- list(train = dtrain, test = dtest)
-
-# Method 1 of training with built-in multiclass objective
-# Note: need to turn off boost from average to match custom objective
-# (https://github.com/microsoft/LightGBM/issues/1846)
-model_builtin <- lgb.train(
-    list()
-    , dtrain
-    , boost_from_average = FALSE
-    , 100L
-    , valids
-    , min_data = 1L
-    , learning_rate = 1.0
-    , early_stopping_rounds = 10L
-    , objective = "multiclass"
-    , metric = "multi_logloss"
-    , num_class = 3L
-)
-
-preds_builtin <- predict(model_builtin, test[, 1L:4L], rawscore = TRUE, reshape = TRUE)
-probs_builtin <- exp(preds_builtin) / rowSums(exp(preds_builtin))
-
-# Method 2 of training with custom objective function
-
-# User defined objective function, given prediction, return gradient and second order gradient
-custom_multiclass_obj <- function(preds, dtrain) {
-    labels <- getinfo(dtrain, "label")
-
-    # preds is a matrix with rows corresponding to samples and columns corresponding to choices
-    preds <- matrix(preds, nrow = length(labels))
-
-    # to prevent overflow, normalize preds by row
-    preds <- preds - apply(preds, MARGIN = 1L, max)
-    prob <- exp(preds) / rowSums(exp(preds))
-
-    # compute gradient
-    grad <- prob
-    subset_index <- as.matrix(
-        data.frame(
-            seq_len(length(labels))
-            , labels + 1L
-            , fix.empty.names = FALSE
-        )
-        , nrow = length(labels)
-        , dimnames = NULL
-    )
-    grad[subset_index] <- grad[subset_index] - 1L
-
-    # compute hessian (approximation)
-    hess <- 2.0 * prob * (1.0 - prob)
-
-    return(list(grad = grad, hess = hess))
-}
-
-# define custom metric
-custom_multiclass_metric <- function(preds, dtrain) {
-    labels <- getinfo(dtrain, "label")
-    preds <- matrix(preds, nrow = length(labels))
-    preds <- preds - apply(preds, 1L, max)
-    prob <- exp(preds) / rowSums(exp(preds))
-
-    subset_index <- as.matrix(
-        data.frame(
-            seq_len(length(labels))
-            , labels + 1L
-            , fix.empty.names = FALSE
-        )
-        , nrow = length(labels)
-        , dimnames = NULL
-    )
-    return(list(
-        name = "error"
-        , value = -mean(log(prob[subset_index]))
-        , higher_better = FALSE
-    ))
-}
-
-model_custom <- lgb.train(
-    list()
-    , dtrain
-    , 100L
-    , valids
-    , min_data = 1L
-    , learning_rate = 1.0
-    , early_stopping_rounds = 10L
-    , objective = custom_multiclass_obj
-    , eval = custom_multiclass_metric
-    , num_class = 3L
-)
-
-preds_custom <- predict(model_custom, test[, 1L:4L], rawscore = TRUE, reshape = TRUE)
-probs_custom <- exp(preds_custom) / rowSums(exp(preds_custom))
-
-# compare predictions
-stopifnot(identical(probs_builtin, probs_custom))
-stopifnot(identical(preds_builtin, preds_custom))
diff --git a/R-package/demo/weight_param.R b/R-package/demo/weight_param.R
deleted file mode 100644
index 461b8caa7..000000000
--- a/R-package/demo/weight_param.R
+++ /dev/null
@@ -1,113 +0,0 @@
-# This demo R code is to provide a demonstration of hyperparameter adjustment
-# when scaling weights for appropriate learning
-# As with any optimizers, bad parameters can impair performance
-
-# Load library
-library(lightgbm)
-
-# We will train a model with the following scenarii:
-# - Run 1: sum of weights equal to 0.06513 without adjusted regularization (not learning)
-# - Run 2: sum of weights equal to 0.06513 with adjusted regularization (learning)
-# - Run 3: sum of weights equal to 6513 (x 1e5) with adjusted regularization (learning)
-
-# Setup small weights
-weights1 <- rep(1.0 / 100000.0, 6513L)
-weights2 <- rep(1.0 / 100000.0, 1611L)
-
-# Load data and create datasets
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label, weight = weights1)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label, weight = weights2)
-valids <- list(test = dtest)
-
-# Run 1: sum of weights equal to 0.06513 without adjusted regularization (not learning)
-# It cannot learn because regularization is too large!
-# min_sum_hessian alone is bigger than the sum of weights, thus you will never learn anything
-params <- list(
-    objective = "regression"
-    , metric = "l2"
-    , device = "cpu"
-    , min_sum_hessian = 10.0
-    , num_leaves = 7L
-    , max_depth = 3L
-    , nthread = 1L
-)
-model <- lgb.train(
-    params
-    , dtrain
-    , 50L
-    , valids
-    , min_data = 1L
-    , learning_rate = 1.0
-    , early_stopping_rounds = 10L
-)
-weight_loss <- as.numeric(model$record_evals$test$l2$eval)
-plot(weight_loss) # Shows how poor the learning was: a straight line!
-
-# Run 2: sum of weights equal to 0.06513 with adjusted regularization (learning)
-# Adjusted regularization just consisting in multiplicating results by 1e4 (x10000)
-# Notice how it learns, there is no issue as we adjusted regularization ourselves
-params <- list(
-    objective = "regression"
-    , metric = "l2"
-    , device = "cpu"
-    , min_sum_hessian = 1e-4
-    , num_leaves = 7L
-    , max_depth = 3L
-    , nthread = 1L
-)
-model <- lgb.train(
-    params
-    , dtrain
-    , 50L
-    , valids
-    , min_data = 1L
-    , learning_rate = 1.0
-    , early_stopping_rounds = 10L
-)
-small_weight_loss <- as.numeric(model$record_evals$test$l2$eval)
-plot(small_weight_loss) # It learns!
-
-# Run 3: sum of weights equal to 6513 (x 1e5) with adjusted regularization (learning)
-# To make it better, we are first cleaning the environment and reloading LightGBM
-lgb.unloader(wipe = TRUE)
-
-# And now, we are doing as usual
-library(lightgbm)
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-valids <- list(test = dtest)
-
-# Setup parameters and run model...
-params <- list(
-    objective = "regression"
-    , metric = "l2"
-    , device = "cpu"
-    , min_sum_hessian = 10.0
-    , num_leaves = 7L
-    , max_depth = 3L
-    , nthread = 1L
-)
-model <- lgb.train(
-    params
-    , dtrain
-    , 50L
-    , valids
-    , min_data = 1L
-    , learning_rate = 1.0
-    , early_stopping_rounds = 10L
-)
-large_weight_loss <- as.numeric(model$record_evals$test$l2$eval)
-plot(large_weight_loss) # It learns!
-
-
-# Do you want to compare the learning? They both converge.
-plot(small_weight_loss, large_weight_loss)
-curve(1.0 * x, from = 0L, to = 0.02, add = TRUE)
diff --git a/R-package/inst/Makevars b/R-package/inst/Makevars
deleted file mode 100644
index 8b1378917..000000000
--- a/R-package/inst/Makevars
+++ /dev/null
@@ -1,1 +0,0 @@
-
diff --git a/R-package/inst/Makevars.win b/R-package/inst/Makevars.win
deleted file mode 100644
index 8b1378917..000000000
--- a/R-package/inst/Makevars.win
+++ /dev/null
@@ -1,1 +0,0 @@
-
diff --git a/R-package/inst/bin/.gitkeep b/R-package/inst/bin/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/R-package/inst/make-r-def.R b/R-package/inst/make-r-def.R
deleted file mode 100644
index 94f548a51..000000000
--- a/R-package/inst/make-r-def.R
+++ /dev/null
@@ -1,98 +0,0 @@
-# [description]
-#     Create a definition file (.def) from a .dll file, using objdump.
-#
-# [usage]
-#
-#     Rscript make-r-def.R something.dll something.def
-#
-# [references]
-#    * https://www.cs.colorado.edu/~main/cs1300/doc/mingwfaq.html
-
-args <- commandArgs(trailingOnly = TRUE)
-
-IN_DLL_FILE <- args[[1L]]
-OUT_DEF_FILE <- args[[2L]]
-DLL_BASE_NAME <- basename(IN_DLL_FILE)
-
-message(sprintf("Creating '%s' from '%s'", OUT_DEF_FILE, IN_DLL_FILE))
-
-# system() will not raise an R exception if the process called
-# fails. Wrapping it here to get that behavior.
-#
-# system() introduces a lot of overhead, at least on Windows,
-# so trying processx if it is available
-.pipe_shell_command_to_stdout <- function(command, args, out_file) {
-    has_processx <- suppressMessages({
-      suppressWarnings({
-        require("processx")  # nolint
-      })
-    })
-    if (has_processx) {
-        p <- processx::process$new(
-            command = command
-            , args = args
-            , stdout = out_file
-            , windows_verbatim_args = FALSE
-        )
-        invisible(p$wait())
-    } else {
-        message(paste0(
-          "Using system2() to run shell commands. Installing "
-          , "'processx' with install.packages('processx') might "
-          , "make this faster."
-        ))
-        # shQuote() is necessary here since one of the arguments
-        # is a file-path to R.dll, which may have spaces. processx
-        # does such quoting but system2() does not
-        exit_code <- system2(
-            command = command
-            , args = shoQuote(args)
-            , stdout = out_file
-        )
-        if (exit_code != 0L) {
-            stop(paste0("Command failed with exit code: ", exit_code))
-        }
-    }
-    return(invisible(NULL))
-}
-
-# use objdump to dump all the symbols
-OBJDUMP_FILE <- "objdump-out.txt"
-.pipe_shell_command_to_stdout(
-    command = "objdump"
-    , args = c("-p", IN_DLL_FILE)
-    , out_file = OBJDUMP_FILE
-)
-
-objdump_results <- readLines(OBJDUMP_FILE)
-invisible(file.remove(OBJDUMP_FILE))
-
-# Only one table in the objdump results matters for our purposes,
-# see https://www.cs.colorado.edu/~main/cs1300/doc/mingwfaq.html
-start_index <- which(
-    grepl(
-        pattern = "[Ordinal/Name Pointer] Table"
-        , x = objdump_results
-        , fixed = TRUE
-    )
-)
-empty_lines <- which(objdump_results == "")
-end_of_table <- empty_lines[empty_lines > start_index][1L]
-
-# Read the contents of the table
-exported_symbols <- objdump_results[(start_index + 1L):end_of_table]
-exported_symbols <- gsub("\t", "", exported_symbols)
-exported_symbols <- gsub(".*\\] ", "", exported_symbols)
-exported_symbols <- gsub(" ", "", exported_symbols)
-
-# Write R.def file
-writeLines(
-    text = c(
-        paste0("LIBRARY \"", DLL_BASE_NAME, "\"")
-        , "EXPORTS"
-        , exported_symbols
-    )
-    , con = OUT_DEF_FILE
-    , sep = "\n"
-)
-message(sprintf("Successfully created '%s'", OUT_DEF_FILE))
diff --git a/R-package/man/agaricus.train.Rd b/R-package/man/agaricus.train.Rd
deleted file mode 100644
index 62b7d05a0..000000000
--- a/R-package/man/agaricus.train.Rd
+++ /dev/null
@@ -1,31 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lightgbm.R
-\docType{data}
-\name{agaricus.train}
-\alias{agaricus.train}
-\title{Training part from Mushroom Data Set}
-\format{
-A list containing a label vector, and a dgCMatrix object with 6513
-rows and 127 variables
-}
-\usage{
-data(agaricus.train)
-}
-\description{
-This data set is originally from the Mushroom data set,
-             UCI Machine Learning Repository.
-             This data set includes the following fields:
-
-              \itemize{
-                  \item{\code{label}: the label for each record}
-                  \item{\code{data}: a sparse Matrix of \code{dgCMatrix} class, with 126 columns.}
-               }
-}
-\references{
-https://archive.ics.uci.edu/ml/datasets/Mushroom
-
-Bache, K. & Lichman, M. (2013). UCI Machine Learning Repository
-[http://archive.ics.uci.edu/ml]. Irvine, CA: University of California,
-School of Information and Computer Science.
-}
-\keyword{datasets}
diff --git a/R-package/man/bank.Rd b/R-package/man/bank.Rd
deleted file mode 100644
index 3b4c13b24..000000000
--- a/R-package/man/bank.Rd
+++ /dev/null
@@ -1,26 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lightgbm.R
-\docType{data}
-\name{bank}
-\alias{bank}
-\title{Bank Marketing Data Set}
-\format{
-A data.table with 4521 rows and 17 variables
-}
-\usage{
-data(bank)
-}
-\description{
-This data set is originally from the Bank Marketing data set,
-             UCI Machine Learning Repository.
-
-             It contains only the following: bank.csv with 10% of the examples and 17 inputs,
-             randomly selected from 3 (older version of this dataset with less inputs).
-}
-\references{
-http://archive.ics.uci.edu/ml/datasets/Bank+Marketing
-
-S. Moro, P. Cortez and P. Rita. (2014)
-A Data-Driven Approach to Predict the Success of Bank Telemarketing. Decision Support Systems
-}
-\keyword{datasets}
diff --git a/R-package/man/dim.Rd b/R-package/man/dim.Rd
deleted file mode 100644
index a1059353a..000000000
--- a/R-package/man/dim.Rd
+++ /dev/null
@@ -1,34 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Dataset.R
-\name{dim.lgb.Dataset}
-\alias{dim.lgb.Dataset}
-\title{Dimensions of an \code{lgb.Dataset}}
-\usage{
-\method{dim}{lgb.Dataset}(x, ...)
-}
-\arguments{
-\item{x}{Object of class \code{lgb.Dataset}}
-
-\item{...}{other parameters}
-}
-\value{
-a vector of numbers of rows and of columns
-}
-\description{
-Returns a vector of numbers of rows and of columns in an \code{lgb.Dataset}.
-}
-\details{
-Note: since \code{nrow} and \code{ncol} internally use \code{dim}, they can also
-be directly used with an \code{lgb.Dataset} object.
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-
-stopifnot(nrow(dtrain) == nrow(train$data))
-stopifnot(ncol(dtrain) == ncol(train$data))
-stopifnot(all(dim(dtrain) == dim(train$data)))
-}
-}
diff --git a/R-package/man/dimnames.lgb.Dataset.Rd b/R-package/man/dimnames.lgb.Dataset.Rd
deleted file mode 100644
index ec01a04f6..000000000
--- a/R-package/man/dimnames.lgb.Dataset.Rd
+++ /dev/null
@@ -1,40 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Dataset.R
-\name{dimnames.lgb.Dataset}
-\alias{dimnames.lgb.Dataset}
-\alias{dimnames<-.lgb.Dataset}
-\title{Handling of column names of \code{lgb.Dataset}}
-\usage{
-\method{dimnames}{lgb.Dataset}(x)
-
-\method{dimnames}{lgb.Dataset}(x) <- value
-}
-\arguments{
-\item{x}{object of class \code{lgb.Dataset}}
-
-\item{value}{a list of two elements: the first one is ignored
-and the second one is column names}
-}
-\value{
-A list with the dimension names of the dataset
-}
-\description{
-Only column names are supported for \code{lgb.Dataset}, thus setting of
-             row names would have no effect and returned row names would be NULL.
-}
-\details{
-Generic \code{dimnames} methods are used by \code{colnames}.
-Since row names are irrelevant, it is recommended to use \code{colnames} directly.
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-lgb.Dataset.construct(dtrain)
-dimnames(dtrain)
-colnames(dtrain)
-colnames(dtrain) <- make.names(seq_len(ncol(train$data)))
-print(dtrain, verbose = TRUE)
-}
-}
diff --git a/R-package/man/figures/logo.svg b/R-package/man/figures/logo.svg
deleted file mode 100644
index 4af239496..000000000
--- a/R-package/man/figures/logo.svg
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<!-- Creator: CorelDRAW 2020 (64-Bit Evaluation Version) -->
-<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="8442px" height="9748px" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
-viewBox="0 0 8438.53 9743.98"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:xodm="http://www.corel.com/coreldraw/odm/2003">
- <defs>
-  <style type="text/css">
-   <![CDATA[
-    .str0 {stroke:#373435;stroke-width:2.36;stroke-miterlimit:22.9256}
-    .fil1 {fill:#373435}
-    .fil5 {fill:#EF4A37}
-    .fil3 {fill:#1B9AD7}
-    .fil2 {fill:#76B644}
-    .fil0 {fill:#FCB518}
-    .fil4 {fill:#E6E7E8;fill-rule:nonzero}
-   ]]>
-  </style>
- </defs>
- <g id="图层_x0020_1">
-  <metadata id="CorelCorpID_0Corel-Layer"/>
-  <polygon class="fil0" points="4219.26,0 6328.9,1218 8438.53,2435.99 8438.53,4871.99 8438.53,7307.98 6328.9,8525.98 4219.26,9743.98 2109.63,8525.98 0,7307.98 0,4871.99 0,2435.99 2109.63,1218 "/>
-  <polygon class="fil1 str0" points="4219.26,287 6204.62,1433.25 8189.98,2579.5 8189.98,4871.99 8189.98,7164.48 6204.62,8310.72 4219.26,9456.97 2233.91,8310.72 248.55,7164.48 248.55,4871.99 248.55,2579.5 2233.91,1433.25 "/>
-  <polygon class="fil2" points="3906.02,3183.13 5436.73,2190.94 5436.73,3483.55 "/>
-  <polygon class="fil0" points="2815.23,5749.77 5436.74,5749.77 5436.74,4071.86 "/>
-  <polygon class="fil3" points="4345.88,3965.45 2815.16,4957.64 2815.16,3665.03 "/>
-  <g id="_1713672554880">
-   <path class="fil4" d="M7626.3 7313.8l-194.4 0 0 -467.44c0,-89.77 -12.58,-154.96 -38.02,-194.98 -25.45,-40.31 -68.33,-60.32 -128.66,-60.32 -50.89,0 -94.05,25.44 -129.51,76.05 -35.45,50.88 -53.17,111.78 -53.17,182.68l0 464.01 -194.98 0 0 -483.17c0,-159.81 -56.32,-239.57 -169.25,-239.57 -52.61,0 -95.78,24.01 -129.52,72.04 -33.73,48.03 -50.6,110.07 -50.6,186.69l0 464.01 -194.4 0 0 -857.68 194.4 0 0 135.79 3.44 0c62.03,-104.06 152.09,-155.81 270.45,-155.81 59.18,0 110.93,16.3 155.53,48.89 44.31,32.59 74.61,75.48 90.63,128.65 63.75,-118.36 158.67,-177.54 285.03,-177.54 188.69,0 283.03,116.36 283.03,349.08l0 528.62z"/>
-   <path class="fil4" d="M5535 7189.72l-3.43 0 0 124.08 -194.41 0 0 -1269.66 194.41 0 0 562.64 3.43 0c66.33,-113.78 163.53,-170.68 291.33,-170.68 108.35,0 193.26,38.31 254.15,115.22 61.19,76.62 91.78,179.54 91.78,308.47 0,143.53 -34.31,258.45 -102.92,344.8 -68.62,86.05 -162.39,129.22 -281.32,129.22 -111.79,0 -196.12,-48.03 -253.02,-144.09zm-5.14 -340.79l0 106.35c0,62.62 20.01,115.51 60.03,159.25 39.74,43.45 90.63,65.19 151.81,65.19 72.05,0 128.65,-28.03 169.82,-84.06 40.89,-56.04 61.47,-134.37 61.47,-235 0,-84.34 -19.15,-150.39 -57.46,-198.13 -38.03,-47.74 -90.06,-71.47 -155.24,-71.47 -69.19,0 -124.94,24.58 -167.25,73.47 -42.03,49.17 -63.18,110.64 -63.18,184.4z"/>
-   <path class="fil4" d="M4150.5 7304.65c-37.74,18.87 -87.77,28.3 -149.8,28.3 -166.4,0 -249.59,-79.76 -249.59,-239.58l0 -484.88 -143.24 0 0 -152.37 143.24 0 0 -198.42 194.41 -55.46 0 253.88 204.98 0 0 152.37 -204.98 0 0 428.85c0,50.89 9.14,87.2 27.44,108.92 18.58,21.73 49.17,32.59 92.34,32.59 32.88,0 61.19,-9.43 85.2,-28.3l0 154.1z"/>
-   <path class="fil4" d="M3435.32 7313.8l-194.12 0 0 -469.16c0,-169.53 -56.89,-254.44 -170.11,-254.44 -56.89,0 -104.92,24.59 -144.09,73.76 -39.16,48.89 -58.6,111.78 -58.6,188.41l0 461.43 -195.27 0 0 -1269.66 195.27 0 0 554.35 3.43 0c64.61,-108.35 157.52,-162.39 277.88,-162.39 190.41,0 285.61,116.36 285.61,349.08l0 528.62z"/>
-   <polygon class="fil4" points="1482.64,7313.8 1288.23,7313.8 1288.23,6456.12 1482.64,6456.12 "/>
-   <path class="fil4" d="M1386.29 6276c-31.73,0 -58.89,-10.29 -81.48,-30.88 -22.87,-20.87 -34.02,-46.88 -34.02,-78.9 0,-31.74 11.15,-58.32 34.02,-79.48 22.59,-21.16 49.75,-31.73 81.48,-31.73 32.88,0 60.9,10.57 83.77,31.73 22.87,21.16 34.31,47.74 34.31,79.48 0,30.3 -11.44,56.04 -34.31,77.47 -22.87,21.45 -50.89,32.31 -83.77,32.31z"/>
-   <polygon class="fil4" points="1112.75,7313.8 917.48,7313.8 917.48,6044.14 1112.75,6044.14 "/>
-   <path class="fil4" d="M2496.58 7245.18c0,314.77 -158.39,472.3 -474.87,472.3 -111.79,0 -209.28,-18.58 -292.48,-56.04l0 -177.54c93.78,53.47 182.98,80.34 267.32,80.34 203.84,0 305.62,-100.35 305.62,-300.76l0 -93.77 -3.43 0c-64.05,109.5 -160.68,164.1 -289.61,164.1 -104.36,0 -188.7,-38.02 -252.73,-114.36 -63.76,-76.05 -95.78,-178.4 -95.78,-306.76 0,-145.81 34.31,-261.6 102.92,-347.65 68.9,-86.05 163.25,-128.94 283.32,-128.94 113.22,0 197.27,46.32 251.88,138.94l3.43 0 0 -118.92 194.41 0 0 789.06zm-192.7 -324.2l0 -111.5c0,-60.32 -20.01,-111.78 -59.75,-154.38 -40.02,-42.89 -89.77,-64.04 -149.52,-64.04 -73.76,0 -131.51,27.16 -172.97,81.48 -41.74,54.6 -62.61,130.65 -62.61,228.43 0,84.33 20.02,151.52 60.04,202.12 39.74,50.61 92.91,75.76 158.67,75.76 66.9,0 121.51,-24.01 163.25,-72.32 42.02,-48.32 62.89,-110.08 62.89,-185.55z"/>
-   <path class="fil4" d="M5165.09 7245.18c0,314.77 -158.38,472.3 -474.87,472.3 -111.78,0 -209.27,-18.58 -292.47,-56.04l0 -177.54c93.77,53.47 182.97,80.34 267.31,80.34 203.84,0 305.62,-100.35 305.62,-300.76l0 -93.77 -3.43 0c-64.04,109.5 -160.67,164.1 -289.61,164.1 -104.35,0 -188.69,-38.02 -252.73,-114.36 -63.76,-76.05 -95.78,-178.4 -95.78,-306.76 0,-145.81 34.31,-261.6 102.93,-347.65 68.9,-86.05 163.24,-128.94 283.32,-128.94 113.21,0 197.27,46.32 251.87,138.94l3.43 0 0 -118.92 194.41 0 0 789.06zm-192.69 -324.2l0 -111.5c0,-60.32 -20.02,-111.78 -59.75,-154.38 -40.03,-42.89 -89.77,-64.04 -149.53,-64.04 -73.76,0 -131.51,27.16 -172.96,81.48 -41.74,54.6 -62.61,130.65 -62.61,228.43 0,84.33 20.01,151.52 60.03,202.12 39.74,50.61 92.92,75.76 158.67,75.76 66.9,0 121.51,-24.01 163.25,-72.32 42.03,-48.32 62.9,-110.08 62.9,-185.55z"/>
-  </g>
-  <polygon class="fil5" points="2814.64,3068.81 2814.64,1388.62 5436.7,1388.62 "/>
- </g>
-</svg>
diff --git a/R-package/man/getinfo.Rd b/R-package/man/getinfo.Rd
deleted file mode 100644
index 6dadaae9b..000000000
--- a/R-package/man/getinfo.Rd
+++ /dev/null
@@ -1,52 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Dataset.R
-\name{getinfo}
-\alias{getinfo}
-\alias{getinfo.lgb.Dataset}
-\title{Get information of an \code{lgb.Dataset} object}
-\usage{
-getinfo(dataset, ...)
-
-\method{getinfo}{lgb.Dataset}(dataset, name, ...)
-}
-\arguments{
-\item{dataset}{Object of class \code{lgb.Dataset}}
-
-\item{...}{other parameters}
-
-\item{name}{the name of the information field to get (see details)}
-}
-\value{
-info data
-}
-\description{
-Get one attribute of a \code{lgb.Dataset}
-}
-\details{
-The \code{name} field can be one of the following:
-
-\itemize{
-    \item \code{label}: label lightgbm learn from ;
-    \item \code{weight}: to do a weight rescale ;
-    \item{\code{group}: used for learning-to-rank tasks. An integer vector describing how to
-        group rows together as ordered results from the same set of candidate results to be ranked.
-        For example, if you have a 100-document dataset with \code{group = c(10, 20, 40, 10, 10, 10)},
-        that means that you have 6 groups, where the first 10 records are in the first group,
-        records 11-30 are in the second group, etc.}
-    \item \code{init_score}: initial score is the base prediction lightgbm will boost from.
-}
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-lgb.Dataset.construct(dtrain)
-
-labels <- lightgbm::getinfo(dtrain, "label")
-lightgbm::setinfo(dtrain, "label", 1 - labels)
-
-labels2 <- lightgbm::getinfo(dtrain, "label")
-stopifnot(all(labels2 == 1 - labels))
-}
-}
diff --git a/R-package/man/lgb.Dataset.Rd b/R-package/man/lgb.Dataset.Rd
deleted file mode 100644
index 4a5abcf78..000000000
--- a/R-package/man/lgb.Dataset.Rd
+++ /dev/null
@@ -1,63 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Dataset.R
-\name{lgb.Dataset}
-\alias{lgb.Dataset}
-\title{Construct \code{lgb.Dataset} object}
-\usage{
-lgb.Dataset(
-  data,
-  params = list(),
-  reference = NULL,
-  colnames = NULL,
-  categorical_feature = NULL,
-  free_raw_data = TRUE,
-  info = list(),
-  ...
-)
-}
-\arguments{
-\item{data}{a \code{matrix} object, a \code{dgCMatrix} object or a character representing a filename}
-
-\item{params}{a list of parameters. See
-\href{https://lightgbm.readthedocs.io/en/latest/Parameters.html#dataset-parameters}{
-The "Dataset Parameters" section of the documentation} for a list of parameters
-and valid values.}
-
-\item{reference}{reference dataset. When LightGBM creates a Dataset, it does some preprocessing like binning
-continuous features into histograms. If you want to apply the same bin boundaries from an existing
-dataset to new \code{data}, pass that existing Dataset to this argument.}
-
-\item{colnames}{names of columns}
-
-\item{categorical_feature}{categorical features. This can either be a character vector of feature
-names or an integer vector with the indices of the features (e.g.
-\code{c(1L, 10L)} to say "the first and tenth columns").}
-
-\item{free_raw_data}{LightGBM constructs its data format, called a "Dataset", from tabular data.
-By default, that Dataset object on the R side does not keep a copy of the raw data.
-This reduces LightGBM's memory consumption, but it means that the Dataset object
-cannot be changed after it has been constructed. If you'd prefer to be able to
-change the Dataset object after construction, set \code{free_raw_data = FALSE}.}
-
-\item{info}{a list of information of the \code{lgb.Dataset} object}
-
-\item{...}{other information to pass to \code{info} or parameters pass to \code{params}}
-}
-\value{
-constructed dataset
-}
-\description{
-Construct \code{lgb.Dataset} object from dense matrix, sparse matrix
-             or local file (that was created previously by saving an \code{lgb.Dataset}).
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data_file <- tempfile(fileext = ".data")
-lgb.Dataset.save(dtrain, data_file)
-dtrain <- lgb.Dataset(data_file)
-lgb.Dataset.construct(dtrain)
-}
-}
diff --git a/R-package/man/lgb.Dataset.construct.Rd b/R-package/man/lgb.Dataset.construct.Rd
deleted file mode 100644
index 97c9e7887..000000000
--- a/R-package/man/lgb.Dataset.construct.Rd
+++ /dev/null
@@ -1,25 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Dataset.R
-\name{lgb.Dataset.construct}
-\alias{lgb.Dataset.construct}
-\title{Construct Dataset explicitly}
-\usage{
-lgb.Dataset.construct(dataset)
-}
-\arguments{
-\item{dataset}{Object of class \code{lgb.Dataset}}
-}
-\value{
-constructed dataset
-}
-\description{
-Construct Dataset explicitly
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-lgb.Dataset.construct(dtrain)
-}
-}
diff --git a/R-package/man/lgb.Dataset.create.valid.Rd b/R-package/man/lgb.Dataset.create.valid.Rd
deleted file mode 100644
index ce34908e1..000000000
--- a/R-package/man/lgb.Dataset.create.valid.Rd
+++ /dev/null
@@ -1,33 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Dataset.R
-\name{lgb.Dataset.create.valid}
-\alias{lgb.Dataset.create.valid}
-\title{Construct validation data}
-\usage{
-lgb.Dataset.create.valid(dataset, data, info = list(), ...)
-}
-\arguments{
-\item{dataset}{\code{lgb.Dataset} object, training data}
-
-\item{data}{a \code{matrix} object, a \code{dgCMatrix} object or a character representing a filename}
-
-\item{info}{a list of information of the \code{lgb.Dataset} object}
-
-\item{...}{other information to pass to \code{info}.}
-}
-\value{
-constructed dataset
-}
-\description{
-Construct validation data according to training data
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-}
-}
diff --git a/R-package/man/lgb.Dataset.save.Rd b/R-package/man/lgb.Dataset.save.Rd
deleted file mode 100644
index 5ea38227b..000000000
--- a/R-package/man/lgb.Dataset.save.Rd
+++ /dev/null
@@ -1,28 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Dataset.R
-\name{lgb.Dataset.save}
-\alias{lgb.Dataset.save}
-\title{Save \code{lgb.Dataset} to a binary file}
-\usage{
-lgb.Dataset.save(dataset, fname)
-}
-\arguments{
-\item{dataset}{object of class \code{lgb.Dataset}}
-
-\item{fname}{object filename of output file}
-}
-\value{
-the dataset you passed in
-}
-\description{
-Please note that \code{init_score} is not saved in binary file.
-             If you need it, please set it again after loading Dataset.
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-lgb.Dataset.save(dtrain, tempfile(fileext = ".bin"))
-}
-}
diff --git a/R-package/man/lgb.Dataset.set.categorical.Rd b/R-package/man/lgb.Dataset.set.categorical.Rd
deleted file mode 100644
index 26eb10770..000000000
--- a/R-package/man/lgb.Dataset.set.categorical.Rd
+++ /dev/null
@@ -1,33 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Dataset.R
-\name{lgb.Dataset.set.categorical}
-\alias{lgb.Dataset.set.categorical}
-\title{Set categorical feature of \code{lgb.Dataset}}
-\usage{
-lgb.Dataset.set.categorical(dataset, categorical_feature)
-}
-\arguments{
-\item{dataset}{object of class \code{lgb.Dataset}}
-
-\item{categorical_feature}{categorical features. This can either be a character vector of feature
-names or an integer vector with the indices of the features (e.g.
-\code{c(1L, 10L)} to say "the first and tenth columns").}
-}
-\value{
-the dataset you passed in
-}
-\description{
-Set the categorical features of an \code{lgb.Dataset} object. Use this function
-             to tell LightGBM which features should be treated as categorical.
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data_file <- tempfile(fileext = ".data")
-lgb.Dataset.save(dtrain, data_file)
-dtrain <- lgb.Dataset(data_file)
-lgb.Dataset.set.categorical(dtrain, 1L:2L)
-}
-}
diff --git a/R-package/man/lgb.Dataset.set.reference.Rd b/R-package/man/lgb.Dataset.set.reference.Rd
deleted file mode 100644
index ee945b4c3..000000000
--- a/R-package/man/lgb.Dataset.set.reference.Rd
+++ /dev/null
@@ -1,30 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Dataset.R
-\name{lgb.Dataset.set.reference}
-\alias{lgb.Dataset.set.reference}
-\title{Set reference of \code{lgb.Dataset}}
-\usage{
-lgb.Dataset.set.reference(dataset, reference)
-}
-\arguments{
-\item{dataset}{object of class \code{lgb.Dataset}}
-
-\item{reference}{object of class \code{lgb.Dataset}}
-}
-\value{
-the dataset you passed in
-}
-\description{
-If you want to use validation data, you should set reference to training data
-}
-\examples{
-\donttest{
-data(agaricus.train, package ="lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset(test$data, test = train$label)
-lgb.Dataset.set.reference(dtest, dtrain)
-}
-}
diff --git a/R-package/man/lgb.convert_with_rules.Rd b/R-package/man/lgb.convert_with_rules.Rd
deleted file mode 100644
index a8a6a00b9..000000000
--- a/R-package/man/lgb.convert_with_rules.Rd
+++ /dev/null
@@ -1,74 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.convert_with_rules.R
-\name{lgb.convert_with_rules}
-\alias{lgb.convert_with_rules}
-\title{Data preparator for LightGBM datasets with rules (integer)}
-\usage{
-lgb.convert_with_rules(data, rules = NULL)
-}
-\arguments{
-\item{data}{A data.frame or data.table to prepare.}
-
-\item{rules}{A set of rules from the data preparator, if already used. This should be an R list,
-where names are column names in \code{data} and values are named character
-vectors whose names are column values and whose values are new values to
-replace them with.}
-}
-\value{
-A list with the cleaned dataset (\code{data}) and the rules (\code{rules}).
-        Note that the data must be converted to a matrix format (\code{as.matrix}) for input in
-        \code{lgb.Dataset}.
-}
-\description{
-Attempts to prepare a clean dataset to prepare to put in a \code{lgb.Dataset}.
-             Factor, character, and logical columns are converted to integer. Missing values
-             in factors and characters will be filled with 0L. Missing values in logicals
-             will be filled with -1L.
-
-             This function returns and optionally takes in "rules" the describe exactly
-             how to convert values in columns.
-
-             Columns that contain only NA values will be converted by this function but will
-             not show up in the returned \code{rules}.
-
-             NOTE: In previous releases of LightGBM, this function was called \code{lgb.prepare_rules2}.
-}
-\examples{
-\donttest{
-data(iris)
-
-str(iris)
-
-new_iris <- lgb.convert_with_rules(data = iris)
-str(new_iris$data)
-
-data(iris) # Erase iris dataset
-iris$Species[1L] <- "NEW FACTOR" # Introduce junk factor (NA)
-
-# Use conversion using known rules
-# Unknown factors become 0, excellent for sparse datasets
-newer_iris <- lgb.convert_with_rules(data = iris, rules = new_iris$rules)
-
-# Unknown factor is now zero, perfect for sparse datasets
-newer_iris$data[1L, ] # Species became 0 as it is an unknown factor
-
-newer_iris$data[1L, 5L] <- 1.0 # Put back real initial value
-
-# Is the newly created dataset equal? YES!
-all.equal(new_iris$data, newer_iris$data)
-
-# Can we test our own rules?
-data(iris) # Erase iris dataset
-
-# We remapped values differently
-personal_rules <- list(
-  Species = c(
-    "setosa" = 3L
-    , "versicolor" = 2L
-    , "virginica" = 1L
-  )
-)
-newest_iris <- lgb.convert_with_rules(data = iris, rules = personal_rules)
-str(newest_iris$data) # SUCCESS!
-}
-}
diff --git a/R-package/man/lgb.cv.Rd b/R-package/man/lgb.cv.Rd
deleted file mode 100644
index ec606d880..000000000
--- a/R-package/man/lgb.cv.Rd
+++ /dev/null
@@ -1,169 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.cv.R
-\name{lgb.cv}
-\alias{lgb.cv}
-\title{Main CV logic for LightGBM}
-\usage{
-lgb.cv(
-  params = list(),
-  data,
-  nrounds = 100L,
-  nfold = 3L,
-  label = NULL,
-  weight = NULL,
-  obj = NULL,
-  eval = NULL,
-  verbose = 1L,
-  record = TRUE,
-  eval_freq = 1L,
-  showsd = TRUE,
-  stratified = TRUE,
-  folds = NULL,
-  init_model = NULL,
-  colnames = NULL,
-  categorical_feature = NULL,
-  early_stopping_rounds = NULL,
-  callbacks = list(),
-  reset_data = FALSE,
-  ...
-)
-}
-\arguments{
-\item{params}{a list of parameters. See \href{https://lightgbm.readthedocs.io/en/latest/Parameters.html}{
-the "Parameters" section of the documentation} for a list of parameters and valid values.}
-
-\item{data}{a \code{lgb.Dataset} object, used for training. Some functions, such as \code{\link{lgb.cv}},
-may allow you to pass other types of data like \code{matrix} and then separately supply
-\code{label} as a keyword argument.}
-
-\item{nrounds}{number of training rounds}
-
-\item{nfold}{the original dataset is randomly partitioned into \code{nfold} equal size subsamples.}
-
-\item{label}{Vector of labels, used if \code{data} is not an \code{\link{lgb.Dataset}}}
-
-\item{weight}{vector of response values. If not NULL, will set to dataset}
-
-\item{obj}{objective function, can be character or custom objective function. Examples include
-\code{regression}, \code{regression_l1}, \code{huber},
-\code{binary}, \code{lambdarank}, \code{multiclass}, \code{multiclass}}
-
-\item{eval}{evaluation function(s). This can be a character vector, function, or list with a mixture of
-            strings and functions.
-
-            \itemize{
-                \item{\bold{a. character vector}:
-                    If you provide a character vector to this argument, it should contain strings with valid
-                    evaluation metrics.
-                    See \href{https://lightgbm.readthedocs.io/en/latest/Parameters.html#metric}{
-                    The "metric" section of the documentation}
-                    for a list of valid metrics.
-                }
-                \item{\bold{b. function}:
-                     You can provide a custom evaluation function. This
-                     should accept the keyword arguments \code{preds} and \code{dtrain} and should return a named
-                     list with three elements:
-                     \itemize{
-                         \item{\code{name}: A string with the name of the metric, used for printing
-                             and storing results.
-                         }
-                         \item{\code{value}: A single number indicating the value of the metric for the
-                             given predictions and true values
-                         }
-                         \item{
-                             \code{higher_better}: A boolean indicating whether higher values indicate a better fit.
-                             For example, this would be \code{FALSE} for metrics like MAE or RMSE.
-                         }
-                     }
-                }
-                \item{\bold{c. list}:
-                    If a list is given, it should only contain character vectors and functions.
-                    These should follow the requirements from the descriptions above.
-                }
-            }}
-
-\item{verbose}{verbosity for output, if <= 0, also will disable the print of evaluation during training}
-
-\item{record}{Boolean, TRUE will record iteration message to \code{booster$record_evals}}
-
-\item{eval_freq}{evaluation output frequency, only effect when verbose > 0}
-
-\item{showsd}{\code{boolean}, whether to show standard deviation of cross validation}
-
-\item{stratified}{a \code{boolean} indicating whether sampling of folds should be stratified
-by the values of outcome labels.}
-
-\item{folds}{\code{list} provides a possibility to use a list of pre-defined CV folds
-(each element must be a vector of test fold's indices). When folds are supplied,
-the \code{nfold} and \code{stratified} parameters are ignored.}
-
-\item{init_model}{path of model file of \code{lgb.Booster} object, will continue training from this model}
-
-\item{colnames}{feature names, if not null, will use this to overwrite the names in dataset}
-
-\item{categorical_feature}{categorical features. This can either be a character vector of feature
-names or an integer vector with the indices of the features (e.g.
-\code{c(1L, 10L)} to say "the first and tenth columns").}
-
-\item{early_stopping_rounds}{int. Activates early stopping. When this parameter is non-null,
-training will stop if the evaluation of any metric on any validation set
-fails to improve for \code{early_stopping_rounds} consecutive boosting rounds.
-If training stops early, the returned model will have attribute \code{best_iter}
-set to the iteration number of the best iteration.}
-
-\item{callbacks}{List of callback functions that are applied at each iteration.}
-
-\item{reset_data}{Boolean, setting it to TRUE (not the default value) will transform the booster model
-into a predictor model which frees up memory and the original datasets}
-
-\item{...}{other parameters, see Parameters.rst for more information. A few key parameters:
-\itemize{
-    \item{\code{boosting}: Boosting type. \code{"gbdt"}, \code{"rf"}, \code{"dart"} or \code{"goss"}.}
-    \item{\code{num_leaves}: Maximum number of leaves in one tree.}
-    \item{\code{max_depth}: Limit the max depth for tree model. This is used to deal with
-                     overfit when #data is small. Tree still grow by leaf-wise.}
-    \item{\code{num_threads}: Number of threads for LightGBM. For the best speed, set this to
-                 the number of real CPU cores(\code{parallel::detectCores(logical = FALSE)}),
-                 not the number of threads (most CPU using hyper-threading to generate 2 threads
-                 per CPU core).}
-}}
-}
-\value{
-a trained model \code{lgb.CVBooster}.
-}
-\description{
-Cross validation logic used by LightGBM
-}
-\section{Early Stopping}{
-
-
-         "early stopping" refers to stopping the training process if the model's performance on a given
-         validation set does not improve for several consecutive iterations.
-
-         If multiple arguments are given to \code{eval}, their order will be preserved. If you enable
-         early stopping by setting \code{early_stopping_rounds} in \code{params}, by default all
-         metrics will be considered for early stopping.
-
-         If you want to only consider the first metric for early stopping, pass
-         \code{first_metric_only = TRUE} in \code{params}. Note that if you also specify \code{metric}
-         in \code{params}, that metric will be considered the "first" one. If you omit \code{metric},
-         a default metric will be used based on your choice for the parameter \code{obj} (keyword argument)
-         or \code{objective} (passed into \code{params}).
-}
-
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-params <- list(objective = "regression", metric = "l2")
-model <- lgb.cv(
-  params = params
-  , data = dtrain
-  , nrounds = 5L
-  , nfold = 3L
-  , min_data = 1L
-  , learning_rate = 1.0
-)
-}
-}
diff --git a/R-package/man/lgb.dump.Rd b/R-package/man/lgb.dump.Rd
deleted file mode 100644
index 6fbc5cbe9..000000000
--- a/R-package/man/lgb.dump.Rd
+++ /dev/null
@@ -1,42 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Booster.R
-\name{lgb.dump}
-\alias{lgb.dump}
-\title{Dump LightGBM model to json}
-\usage{
-lgb.dump(booster, num_iteration = NULL)
-}
-\arguments{
-\item{booster}{Object of class \code{lgb.Booster}}
-
-\item{num_iteration}{number of iteration want to predict with, NULL or <= 0 means use best iteration}
-}
-\value{
-json format of model
-}
-\description{
-Dump LightGBM model to json
-}
-\examples{
-\donttest{
-library(lightgbm)
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-params <- list(objective = "regression", metric = "l2")
-valids <- list(test = dtest)
-model <- lgb.train(
-  params = params
-  , data = dtrain
-  , nrounds = 10L
-  , valids = valids
-  , min_data = 1L
-  , learning_rate = 1.0
-  , early_stopping_rounds = 5L
-)
-json_model <- lgb.dump(model)
-}
-}
diff --git a/R-package/man/lgb.get.eval.result.Rd b/R-package/man/lgb.get.eval.result.Rd
deleted file mode 100644
index 917e0a403..000000000
--- a/R-package/man/lgb.get.eval.result.Rd
+++ /dev/null
@@ -1,63 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Booster.R
-\name{lgb.get.eval.result}
-\alias{lgb.get.eval.result}
-\title{Get record evaluation result from booster}
-\usage{
-lgb.get.eval.result(
-  booster,
-  data_name,
-  eval_name,
-  iters = NULL,
-  is_err = FALSE
-)
-}
-\arguments{
-\item{booster}{Object of class \code{lgb.Booster}}
-
-\item{data_name}{Name of the dataset to return evaluation results for.}
-
-\item{eval_name}{Name of the evaluation metric to return results for.}
-
-\item{iters}{An integer vector of iterations you want to get evaluation results for. If NULL
-(the default), evaluation results for all iterations will be returned.}
-
-\item{is_err}{TRUE will return evaluation error instead}
-}
-\value{
-numeric vector of evaluation result
-}
-\description{
-Given a \code{lgb.Booster}, return evaluation results for a
-             particular metric on a particular dataset.
-}
-\examples{
-\donttest{
-# train a regression model
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-params <- list(objective = "regression", metric = "l2")
-valids <- list(test = dtest)
-model <- lgb.train(
-  params = params
-  , data = dtrain
-  , nrounds = 5L
-  , valids = valids
-  , min_data = 1L
-  , learning_rate = 1.0
-)
-
-# Examine valid data_name values
-print(setdiff(names(model$record_evals), "start_iter"))
-
-# Examine valid eval_name values for dataset "test"
-print(names(model$record_evals[["test"]]))
-
-# Get L2 values for "test" dataset
-lgb.get.eval.result(model, "test", "l2")
-}
-}
diff --git a/R-package/man/lgb.importance.Rd b/R-package/man/lgb.importance.Rd
deleted file mode 100644
index 2fd5d4938..000000000
--- a/R-package/man/lgb.importance.Rd
+++ /dev/null
@@ -1,48 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.importance.R
-\name{lgb.importance}
-\alias{lgb.importance}
-\title{Compute feature importance in a model}
-\usage{
-lgb.importance(model, percentage = TRUE)
-}
-\arguments{
-\item{model}{object of class \code{lgb.Booster}.}
-
-\item{percentage}{whether to show importance in relative percentage.}
-}
-\value{
-For a tree model, a \code{data.table} with the following columns:
-\itemize{
-  \item{\code{Feature}: Feature names in the model.}
-  \item{\code{Gain}: The total gain of this feature's splits.}
-  \item{\code{Cover}: The number of observation related to this feature.}
-  \item{\code{Frequency}: The number of times a feature splited in trees.}
-}
-}
-\description{
-Creates a \code{data.table} of feature importances in a model.
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-
-params <- list(
-  objective = "binary"
-  , learning_rate = 0.1
-  , max_depth = -1L
-  , min_data_in_leaf = 1L
-  , min_sum_hessian_in_leaf = 1.0
-)
-model <- lgb.train(
-    params = params
-    , data = dtrain
-    , nrounds = 5L
-)
-
-tree_imp1 <- lgb.importance(model, percentage = TRUE)
-tree_imp2 <- lgb.importance(model, percentage = FALSE)
-}
-}
diff --git a/R-package/man/lgb.interprete.Rd b/R-package/man/lgb.interprete.Rd
deleted file mode 100644
index c19052826..000000000
--- a/R-package/man/lgb.interprete.Rd
+++ /dev/null
@@ -1,56 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.interprete.R
-\name{lgb.interprete}
-\alias{lgb.interprete}
-\title{Compute feature contribution of prediction}
-\usage{
-lgb.interprete(model, data, idxset, num_iteration = NULL)
-}
-\arguments{
-\item{model}{object of class \code{lgb.Booster}.}
-
-\item{data}{a matrix object or a dgCMatrix object.}
-
-\item{idxset}{an integer vector of indices of rows needed.}
-
-\item{num_iteration}{number of iteration want to predict with, NULL or <= 0 means use best iteration.}
-}
-\value{
-For regression, binary classification and lambdarank model, a \code{list} of \code{data.table}
-        with the following columns:
-        \itemize{
-            \item{\code{Feature}: Feature names in the model.}
-            \item{\code{Contribution}: The total contribution of this feature's splits.}
-        }
-        For multiclass classification, a \code{list} of \code{data.table} with the Feature column and
-        Contribution columns to each class.
-}
-\description{
-Computes feature contribution components of rawscore prediction.
-}
-\examples{
-\donttest{
-Logit <- function(x) log(x / (1.0 - x))
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-setinfo(dtrain, "init_score", rep(Logit(mean(train$label)), length(train$label)))
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-
-params <- list(
-    objective = "binary"
-    , learning_rate = 0.1
-    , max_depth = -1L
-    , min_data_in_leaf = 1L
-    , min_sum_hessian_in_leaf = 1.0
-)
-model <- lgb.train(
-    params = params
-    , data = dtrain
-    , nrounds = 3L
-)
-
-tree_interpretation <- lgb.interprete(model, test$data, 1L:5L)
-}
-}
diff --git a/R-package/man/lgb.load.Rd b/R-package/man/lgb.load.Rd
deleted file mode 100644
index 72633e7ba..000000000
--- a/R-package/man/lgb.load.Rd
+++ /dev/null
@@ -1,46 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Booster.R
-\name{lgb.load}
-\alias{lgb.load}
-\title{Load LightGBM model}
-\usage{
-lgb.load(filename = NULL, model_str = NULL)
-}
-\arguments{
-\item{filename}{path of model file}
-
-\item{model_str}{a str containing the model}
-}
-\value{
-lgb.Booster
-}
-\description{
-Load LightGBM takes in either a file path or model string.
-              If both are provided, Load will default to loading from file
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-params <- list(objective = "regression", metric = "l2")
-valids <- list(test = dtest)
-model <- lgb.train(
-  params = params
-  , data = dtrain
-  , nrounds = 5L
-  , valids = valids
-  , min_data = 1L
-  , learning_rate = 1.0
-  , early_stopping_rounds = 3L
-)
-model_file <- tempfile(fileext = ".txt")
-lgb.save(model, model_file)
-load_booster <- lgb.load(filename = model_file)
-model_string <- model$save_model_to_string(NULL) # saves best iteration
-load_booster_from_str <- lgb.load(model_str = model_string)
-}
-}
diff --git a/R-package/man/lgb.model.dt.tree.Rd b/R-package/man/lgb.model.dt.tree.Rd
deleted file mode 100644
index c5c88156f..000000000
--- a/R-package/man/lgb.model.dt.tree.Rd
+++ /dev/null
@@ -1,59 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.model.dt.tree.R
-\name{lgb.model.dt.tree}
-\alias{lgb.model.dt.tree}
-\title{Parse a LightGBM model json dump}
-\usage{
-lgb.model.dt.tree(model, num_iteration = NULL)
-}
-\arguments{
-\item{model}{object of class \code{lgb.Booster}}
-
-\item{num_iteration}{number of iterations you want to predict with. NULL or
-<= 0 means use best iteration}
-}
-\value{
-A \code{data.table} with detailed information about model trees' nodes and leafs.
-
-The columns of the \code{data.table} are:
-
-\itemize{
- \item{\code{tree_index}: ID of a tree in a model (integer)}
- \item{\code{split_index}: ID of a node in a tree (integer)}
- \item{\code{split_feature}: for a node, it's a feature name (character);
-                             for a leaf, it simply labels it as \code{"NA"}}
- \item{\code{node_parent}: ID of the parent node for current node (integer)}
- \item{\code{leaf_index}: ID of a leaf in a tree (integer)}
- \item{\code{leaf_parent}: ID of the parent node for current leaf (integer)}
- \item{\code{split_gain}: Split gain of a node}
- \item{\code{threshold}: Splitting threshold value of a node}
- \item{\code{decision_type}: Decision type of a node}
- \item{\code{default_left}: Determine how to handle NA value, TRUE -> Left, FALSE -> Right}
- \item{\code{internal_value}: Node value}
- \item{\code{internal_count}: The number of observation collected by a node}
- \item{\code{leaf_value}: Leaf value}
- \item{\code{leaf_count}: The number of observation collected by a leaf}
-}
-}
-\description{
-Parse a LightGBM model json dump into a \code{data.table} structure.
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-
-params <- list(
-  objective = "binary"
-  , learning_rate = 0.01
-  , num_leaves = 63L
-  , max_depth = -1L
-  , min_data_in_leaf = 1L
-  , min_sum_hessian_in_leaf = 1.0
-)
-model <- lgb.train(params, dtrain, 10L)
-
-tree_dt <- lgb.model.dt.tree(model)
-}
-}
diff --git a/R-package/man/lgb.plot.importance.Rd b/R-package/man/lgb.plot.importance.Rd
deleted file mode 100644
index 4b915e35f..000000000
--- a/R-package/man/lgb.plot.importance.Rd
+++ /dev/null
@@ -1,61 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.plot.importance.R
-\name{lgb.plot.importance}
-\alias{lgb.plot.importance}
-\title{Plot feature importance as a bar graph}
-\usage{
-lgb.plot.importance(
-  tree_imp,
-  top_n = 10L,
-  measure = "Gain",
-  left_margin = 10L,
-  cex = NULL
-)
-}
-\arguments{
-\item{tree_imp}{a \code{data.table} returned by \code{\link{lgb.importance}}.}
-
-\item{top_n}{maximal number of top features to include into the plot.}
-
-\item{measure}{the name of importance measure to plot, can be "Gain", "Cover" or "Frequency".}
-
-\item{left_margin}{(base R barplot) allows to adjust the left margin size to fit feature names.}
-
-\item{cex}{(base R barplot) passed as \code{cex.names} parameter to \code{\link[graphics]{barplot}}.
-Set a number smaller than 1.0 to make the bar labels smaller than R's default and values
-greater than 1.0 to make them larger.}
-}
-\value{
-The \code{lgb.plot.importance} function creates a \code{barplot}
-and silently returns a processed data.table with \code{top_n} features sorted by defined importance.
-}
-\description{
-Plot previously calculated feature importance: Gain, Cover and Frequency, as a bar graph.
-}
-\details{
-The graph represents each feature as a horizontal bar of length proportional to the defined importance of a feature.
-Features are shown ranked in a decreasing importance order.
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-
-params <- list(
-    objective = "binary"
-    , learning_rate = 0.1
-    , min_data_in_leaf = 1L
-    , min_sum_hessian_in_leaf = 1.0
-)
-
-model <- lgb.train(
-    params = params
-    , data = dtrain
-    , nrounds = 5L
-)
-
-tree_imp <- lgb.importance(model, percentage = TRUE)
-lgb.plot.importance(tree_imp, top_n = 5L, measure = "Gain")
-}
-}
diff --git a/R-package/man/lgb.plot.interpretation.Rd b/R-package/man/lgb.plot.interpretation.Rd
deleted file mode 100644
index f82663085..000000000
--- a/R-package/man/lgb.plot.interpretation.Rd
+++ /dev/null
@@ -1,74 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.plot.interpretation.R
-\name{lgb.plot.interpretation}
-\alias{lgb.plot.interpretation}
-\title{Plot feature contribution as a bar graph}
-\usage{
-lgb.plot.interpretation(
-  tree_interpretation_dt,
-  top_n = 10L,
-  cols = 1L,
-  left_margin = 10L,
-  cex = NULL
-)
-}
-\arguments{
-\item{tree_interpretation_dt}{a \code{data.table} returned by \code{\link{lgb.interprete}}.}
-
-\item{top_n}{maximal number of top features to include into the plot.}
-
-\item{cols}{the column numbers of layout, will be used only for multiclass classification feature contribution.}
-
-\item{left_margin}{(base R barplot) allows to adjust the left margin size to fit feature names.}
-
-\item{cex}{(base R barplot) passed as \code{cex.names} parameter to \code{barplot}.}
-}
-\value{
-The \code{lgb.plot.interpretation} function creates a \code{barplot}.
-}
-\description{
-Plot previously calculated feature contribution as a bar graph.
-}
-\details{
-The graph represents each feature as a horizontal bar of length proportional to the defined
-contribution of a feature. Features are shown ranked in a decreasing contribution order.
-}
-\examples{
-\donttest{
-Logit <- function(x) {
-  log(x / (1.0 - x))
-}
-data(agaricus.train, package = "lightgbm")
-labels <- agaricus.train$label
-dtrain <- lgb.Dataset(
-  agaricus.train$data
-  , label = labels
-)
-setinfo(dtrain, "init_score", rep(Logit(mean(labels)), length(labels)))
-
-data(agaricus.test, package = "lightgbm")
-
-params <- list(
-  objective = "binary"
-  , learning_rate = 0.1
-  , max_depth = -1L
-  , min_data_in_leaf = 1L
-  , min_sum_hessian_in_leaf = 1.0
-)
-model <- lgb.train(
-  params = params
-  , data = dtrain
-  , nrounds = 5L
-)
-
-tree_interpretation <- lgb.interprete(
-  model = model
-  , data = agaricus.test$data
-  , idxset = 1L:5L
-)
-lgb.plot.interpretation(
-  tree_interpretation_dt = tree_interpretation[[1L]]
-  , top_n = 3L
-)
-}
-}
diff --git a/R-package/man/lgb.save.Rd b/R-package/man/lgb.save.Rd
deleted file mode 100644
index 9ac19eadb..000000000
--- a/R-package/man/lgb.save.Rd
+++ /dev/null
@@ -1,44 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Booster.R
-\name{lgb.save}
-\alias{lgb.save}
-\title{Save LightGBM model}
-\usage{
-lgb.save(booster, filename, num_iteration = NULL)
-}
-\arguments{
-\item{booster}{Object of class \code{lgb.Booster}}
-
-\item{filename}{saved filename}
-
-\item{num_iteration}{number of iteration want to predict with, NULL or <= 0 means use best iteration}
-}
-\value{
-lgb.Booster
-}
-\description{
-Save LightGBM model
-}
-\examples{
-\donttest{
-library(lightgbm)
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-params <- list(objective = "regression", metric = "l2")
-valids <- list(test = dtest)
-model <- lgb.train(
-  params = params
-  , data = dtrain
-  , nrounds = 10L
-  , valids = valids
-  , min_data = 1L
-  , learning_rate = 1.0
-  , early_stopping_rounds = 5L
-)
-lgb.save(model, tempfile(fileext = ".txt"))
-}
-}
diff --git a/R-package/man/lgb.train.Rd b/R-package/man/lgb.train.Rd
deleted file mode 100644
index 40c7135d3..000000000
--- a/R-package/man/lgb.train.Rd
+++ /dev/null
@@ -1,158 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.train.R
-\name{lgb.train}
-\alias{lgb.train}
-\title{Main training logic for LightGBM}
-\usage{
-lgb.train(
-  params = list(),
-  data,
-  nrounds = 100L,
-  valids = list(),
-  obj = NULL,
-  eval = NULL,
-  verbose = 1L,
-  record = TRUE,
-  eval_freq = 1L,
-  init_model = NULL,
-  colnames = NULL,
-  categorical_feature = NULL,
-  early_stopping_rounds = NULL,
-  callbacks = list(),
-  reset_data = FALSE,
-  ...
-)
-}
-\arguments{
-\item{params}{a list of parameters. See \href{https://lightgbm.readthedocs.io/en/latest/Parameters.html}{
-the "Parameters" section of the documentation} for a list of parameters and valid values.}
-
-\item{data}{a \code{lgb.Dataset} object, used for training. Some functions, such as \code{\link{lgb.cv}},
-may allow you to pass other types of data like \code{matrix} and then separately supply
-\code{label} as a keyword argument.}
-
-\item{nrounds}{number of training rounds}
-
-\item{valids}{a list of \code{lgb.Dataset} objects, used for validation}
-
-\item{obj}{objective function, can be character or custom objective function. Examples include
-\code{regression}, \code{regression_l1}, \code{huber},
-\code{binary}, \code{lambdarank}, \code{multiclass}, \code{multiclass}}
-
-\item{eval}{evaluation function(s). This can be a character vector, function, or list with a mixture of
-            strings and functions.
-
-            \itemize{
-                \item{\bold{a. character vector}:
-                    If you provide a character vector to this argument, it should contain strings with valid
-                    evaluation metrics.
-                    See \href{https://lightgbm.readthedocs.io/en/latest/Parameters.html#metric}{
-                    The "metric" section of the documentation}
-                    for a list of valid metrics.
-                }
-                \item{\bold{b. function}:
-                     You can provide a custom evaluation function. This
-                     should accept the keyword arguments \code{preds} and \code{dtrain} and should return a named
-                     list with three elements:
-                     \itemize{
-                         \item{\code{name}: A string with the name of the metric, used for printing
-                             and storing results.
-                         }
-                         \item{\code{value}: A single number indicating the value of the metric for the
-                             given predictions and true values
-                         }
-                         \item{
-                             \code{higher_better}: A boolean indicating whether higher values indicate a better fit.
-                             For example, this would be \code{FALSE} for metrics like MAE or RMSE.
-                         }
-                     }
-                }
-                \item{\bold{c. list}:
-                    If a list is given, it should only contain character vectors and functions.
-                    These should follow the requirements from the descriptions above.
-                }
-            }}
-
-\item{verbose}{verbosity for output, if <= 0, also will disable the print of evaluation during training}
-
-\item{record}{Boolean, TRUE will record iteration message to \code{booster$record_evals}}
-
-\item{eval_freq}{evaluation output frequency, only effect when verbose > 0}
-
-\item{init_model}{path of model file of \code{lgb.Booster} object, will continue training from this model}
-
-\item{colnames}{feature names, if not null, will use this to overwrite the names in dataset}
-
-\item{categorical_feature}{categorical features. This can either be a character vector of feature
-names or an integer vector with the indices of the features (e.g.
-\code{c(1L, 10L)} to say "the first and tenth columns").}
-
-\item{early_stopping_rounds}{int. Activates early stopping. When this parameter is non-null,
-training will stop if the evaluation of any metric on any validation set
-fails to improve for \code{early_stopping_rounds} consecutive boosting rounds.
-If training stops early, the returned model will have attribute \code{best_iter}
-set to the iteration number of the best iteration.}
-
-\item{callbacks}{List of callback functions that are applied at each iteration.}
-
-\item{reset_data}{Boolean, setting it to TRUE (not the default value) will transform the
-booster model into a predictor model which frees up memory and the
-original datasets}
-
-\item{...}{other parameters, see \href{https://lightgbm.readthedocs.io/en/latest/Parameters.html}{
-the "Parameters" section of the documentation} for more information. A few key parameters:
-\itemize{
-    \item{\code{boosting}: Boosting type. \code{"gbdt"}, \code{"rf"}, \code{"dart"} or \code{"goss"}.}
-    \item{\code{num_leaves}: Maximum number of leaves in one tree.}
-    \item{\code{max_depth}: Limit the max depth for tree model. This is used to deal with
-                     overfitting. Tree still grow by leaf-wise.}
-    \item{\code{num_threads}: Number of threads for LightGBM. For the best speed, set this to
-                 the number of real CPU cores(\code{parallel::detectCores(logical = FALSE)}),
-                 not the number of threads (most CPU using hyper-threading to generate 2 threads
-                 per CPU core).}
-}}
-}
-\value{
-a trained booster model \code{lgb.Booster}.
-}
-\description{
-Logic to train with LightGBM
-}
-\section{Early Stopping}{
-
-
-         "early stopping" refers to stopping the training process if the model's performance on a given
-         validation set does not improve for several consecutive iterations.
-
-         If multiple arguments are given to \code{eval}, their order will be preserved. If you enable
-         early stopping by setting \code{early_stopping_rounds} in \code{params}, by default all
-         metrics will be considered for early stopping.
-
-         If you want to only consider the first metric for early stopping, pass
-         \code{first_metric_only = TRUE} in \code{params}. Note that if you also specify \code{metric}
-         in \code{params}, that metric will be considered the "first" one. If you omit \code{metric},
-         a default metric will be used based on your choice for the parameter \code{obj} (keyword argument)
-         or \code{objective} (passed into \code{params}).
-}
-
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-params <- list(objective = "regression", metric = "l2")
-valids <- list(test = dtest)
-model <- lgb.train(
-  params = params
-  , data = dtrain
-  , nrounds = 5L
-  , valids = valids
-  , min_data = 1L
-  , learning_rate = 1.0
-  , early_stopping_rounds = 3L
-)
-}
-}
diff --git a/R-package/man/lgb.unloader.Rd b/R-package/man/lgb.unloader.Rd
deleted file mode 100644
index d3a0bbd01..000000000
--- a/R-package/man/lgb.unloader.Rd
+++ /dev/null
@@ -1,54 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.unloader.R
-\name{lgb.unloader}
-\alias{lgb.unloader}
-\title{Remove lightgbm and its objects from an environment}
-\usage{
-lgb.unloader(restore = TRUE, wipe = FALSE, envir = .GlobalEnv)
-}
-\arguments{
-\item{restore}{Whether to reload \code{LightGBM} immediately after detaching from R.
-Defaults to \code{TRUE} which means automatically reload \code{LightGBM} once
-unloading is performed.}
-
-\item{wipe}{Whether to wipe all \code{lgb.Dataset} and \code{lgb.Booster} from the global
-environment. Defaults to \code{FALSE} which means to not remove them.}
-
-\item{envir}{The environment to perform wiping on if \code{wipe == TRUE}. Defaults to
-\code{.GlobalEnv} which is the global environment.}
-}
-\value{
-NULL invisibly.
-}
-\description{
-Attempts to unload LightGBM packages so you can remove objects cleanly without
-             having to restart R. This is useful for instance if an object becomes stuck for no
-             apparent reason and you do not want to restart R to fix the lost object.
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-params <- list(objective = "regression", metric = "l2")
-valids <- list(test = dtest)
-model <- lgb.train(
-  params = params
-  , data = dtrain
-  , nrounds = 5L
-  , valids = valids
-  , min_data = 1L
-  , learning_rate = 1.0
-)
-
-lgb.unloader(restore = FALSE, wipe = FALSE, envir = .GlobalEnv)
-rm(model, dtrain, dtest) # Not needed if wipe = TRUE
-gc() # Not needed if wipe = TRUE
-
-library(lightgbm)
-# Do whatever you want again with LightGBM without object clashing
-}
-}
diff --git a/R-package/man/lgb_shared_params.Rd b/R-package/man/lgb_shared_params.Rd
deleted file mode 100644
index e5288e045..000000000
--- a/R-package/man/lgb_shared_params.Rd
+++ /dev/null
@@ -1,88 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lightgbm.R
-\name{lgb_shared_params}
-\alias{lgb_shared_params}
-\title{Shared parameter docs}
-\arguments{
-\item{callbacks}{List of callback functions that are applied at each iteration.}
-
-\item{data}{a \code{lgb.Dataset} object, used for training. Some functions, such as \code{\link{lgb.cv}},
-may allow you to pass other types of data like \code{matrix} and then separately supply
-\code{label} as a keyword argument.}
-
-\item{early_stopping_rounds}{int. Activates early stopping. When this parameter is non-null,
-training will stop if the evaluation of any metric on any validation set
-fails to improve for \code{early_stopping_rounds} consecutive boosting rounds.
-If training stops early, the returned model will have attribute \code{best_iter}
-set to the iteration number of the best iteration.}
-
-\item{eval}{evaluation function(s). This can be a character vector, function, or list with a mixture of
-            strings and functions.
-
-            \itemize{
-                \item{\bold{a. character vector}:
-                    If you provide a character vector to this argument, it should contain strings with valid
-                    evaluation metrics.
-                    See \href{https://lightgbm.readthedocs.io/en/latest/Parameters.html#metric}{
-                    The "metric" section of the documentation}
-                    for a list of valid metrics.
-                }
-                \item{\bold{b. function}:
-                     You can provide a custom evaluation function. This
-                     should accept the keyword arguments \code{preds} and \code{dtrain} and should return a named
-                     list with three elements:
-                     \itemize{
-                         \item{\code{name}: A string with the name of the metric, used for printing
-                             and storing results.
-                         }
-                         \item{\code{value}: A single number indicating the value of the metric for the
-                             given predictions and true values
-                         }
-                         \item{
-                             \code{higher_better}: A boolean indicating whether higher values indicate a better fit.
-                             For example, this would be \code{FALSE} for metrics like MAE or RMSE.
-                         }
-                     }
-                }
-                \item{\bold{c. list}:
-                    If a list is given, it should only contain character vectors and functions.
-                    These should follow the requirements from the descriptions above.
-                }
-            }}
-
-\item{eval_freq}{evaluation output frequency, only effect when verbose > 0}
-
-\item{init_model}{path of model file of \code{lgb.Booster} object, will continue training from this model}
-
-\item{nrounds}{number of training rounds}
-
-\item{obj}{objective function, can be character or custom objective function. Examples include
-\code{regression}, \code{regression_l1}, \code{huber},
-\code{binary}, \code{lambdarank}, \code{multiclass}, \code{multiclass}}
-
-\item{params}{a list of parameters. See \href{https://lightgbm.readthedocs.io/en/latest/Parameters.html}{
-the "Parameters" section of the documentation} for a list of parameters and valid values.}
-
-\item{verbose}{verbosity for output, if <= 0, also will disable the print of evaluation during training}
-}
-\description{
-Parameter docs shared by \code{lgb.train}, \code{lgb.cv}, and \code{lightgbm}
-}
-\section{Early Stopping}{
-
-
-         "early stopping" refers to stopping the training process if the model's performance on a given
-         validation set does not improve for several consecutive iterations.
-
-         If multiple arguments are given to \code{eval}, their order will be preserved. If you enable
-         early stopping by setting \code{early_stopping_rounds} in \code{params}, by default all
-         metrics will be considered for early stopping.
-
-         If you want to only consider the first metric for early stopping, pass
-         \code{first_metric_only = TRUE} in \code{params}. Note that if you also specify \code{metric}
-         in \code{params}, that metric will be considered the "first" one. If you omit \code{metric},
-         a default metric will be used based on your choice for the parameter \code{obj} (keyword argument)
-         or \code{objective} (passed into \code{params}).
-}
-
-\keyword{internal}
diff --git a/R-package/man/lightgbm.Rd b/R-package/man/lightgbm.Rd
deleted file mode 100644
index 6512dbc6b..000000000
--- a/R-package/man/lightgbm.Rd
+++ /dev/null
@@ -1,98 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lightgbm.R
-\name{lightgbm}
-\alias{lightgbm}
-\title{Train a LightGBM model}
-\usage{
-lightgbm(
-  data,
-  label = NULL,
-  weight = NULL,
-  params = list(),
-  nrounds = 100L,
-  verbose = 1L,
-  eval_freq = 1L,
-  early_stopping_rounds = NULL,
-  save_name = "lightgbm.model",
-  init_model = NULL,
-  callbacks = list(),
-  ...
-)
-}
-\arguments{
-\item{data}{a \code{lgb.Dataset} object, used for training. Some functions, such as \code{\link{lgb.cv}},
-may allow you to pass other types of data like \code{matrix} and then separately supply
-\code{label} as a keyword argument.}
-
-\item{label}{Vector of labels, used if \code{data} is not an \code{\link{lgb.Dataset}}}
-
-\item{weight}{vector of response values. If not NULL, will set to dataset}
-
-\item{params}{a list of parameters. See \href{https://lightgbm.readthedocs.io/en/latest/Parameters.html}{
-the "Parameters" section of the documentation} for a list of parameters and valid values.}
-
-\item{nrounds}{number of training rounds}
-
-\item{verbose}{verbosity for output, if <= 0, also will disable the print of evaluation during training}
-
-\item{eval_freq}{evaluation output frequency, only effect when verbose > 0}
-
-\item{early_stopping_rounds}{int. Activates early stopping. When this parameter is non-null,
-training will stop if the evaluation of any metric on any validation set
-fails to improve for \code{early_stopping_rounds} consecutive boosting rounds.
-If training stops early, the returned model will have attribute \code{best_iter}
-set to the iteration number of the best iteration.}
-
-\item{save_name}{File name to use when writing the trained model to disk. Should end in ".model".}
-
-\item{init_model}{path of model file of \code{lgb.Booster} object, will continue training from this model}
-
-\item{callbacks}{List of callback functions that are applied at each iteration.}
-
-\item{...}{Additional arguments passed to \code{\link{lgb.train}}. For example
-\itemize{
-   \item{\code{valids}: a list of \code{lgb.Dataset} objects, used for validation}
-   \item{\code{obj}: objective function, can be character or custom objective function. Examples include
-              \code{regression}, \code{regression_l1}, \code{huber},
-               \code{binary}, \code{lambdarank}, \code{multiclass}, \code{multiclass}}
-   \item{\code{eval}: evaluation function, can be (a list of) character or custom eval function}
-   \item{\code{record}: Boolean, TRUE will record iteration message to \code{booster$record_evals}}
-   \item{\code{colnames}: feature names, if not null, will use this to overwrite the names in dataset}
-   \item{\code{categorical_feature}: categorical features. This can either be a character vector of feature
-                       names or an integer vector with the indices of the features (e.g. \code{c(1L, 10L)} to
-                       say "the first and tenth columns").}
-   \item{\code{reset_data}: Boolean, setting it to TRUE (not the default value) will transform the booster model
-                     into a predictor model which frees up memory and the original datasets}
-    \item{\code{boosting}: Boosting type. \code{"gbdt"}, \code{"rf"}, \code{"dart"} or \code{"goss"}.}
-    \item{\code{num_leaves}: Maximum number of leaves in one tree.}
-    \item{\code{max_depth}: Limit the max depth for tree model. This is used to deal with
-                     overfit when #data is small. Tree still grow by leaf-wise.}
-     \item{\code{num_threads}: Number of threads for LightGBM. For the best speed, set this to
-                        the number of real CPU cores(\code{parallel::detectCores(logical = FALSE)}),
-                        not the number of threads (most CPU using hyper-threading to generate 2 threads
-                        per CPU core).}
-}}
-}
-\value{
-a trained \code{lgb.Booster}
-}
-\description{
-Simple interface for training a LightGBM model.
-}
-\section{Early Stopping}{
-
-
-         "early stopping" refers to stopping the training process if the model's performance on a given
-         validation set does not improve for several consecutive iterations.
-
-         If multiple arguments are given to \code{eval}, their order will be preserved. If you enable
-         early stopping by setting \code{early_stopping_rounds} in \code{params}, by default all
-         metrics will be considered for early stopping.
-
-         If you want to only consider the first metric for early stopping, pass
-         \code{first_metric_only = TRUE} in \code{params}. Note that if you also specify \code{metric}
-         in \code{params}, that metric will be considered the "first" one. If you omit \code{metric},
-         a default metric will be used based on your choice for the parameter \code{obj} (keyword argument)
-         or \code{objective} (passed into \code{params}).
-}
-
diff --git a/R-package/man/predict.lgb.Booster.Rd b/R-package/man/predict.lgb.Booster.Rd
deleted file mode 100644
index c1c4cfb0c..000000000
--- a/R-package/man/predict.lgb.Booster.Rd
+++ /dev/null
@@ -1,83 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Booster.R
-\name{predict.lgb.Booster}
-\alias{predict.lgb.Booster}
-\title{Predict method for LightGBM model}
-\usage{
-\method{predict}{lgb.Booster}(
-  object,
-  data,
-  start_iteration = NULL,
-  num_iteration = NULL,
-  rawscore = FALSE,
-  predleaf = FALSE,
-  predcontrib = FALSE,
-  header = FALSE,
-  reshape = FALSE,
-  ...
-)
-}
-\arguments{
-\item{object}{Object of class \code{lgb.Booster}}
-
-\item{data}{a \code{matrix} object, a \code{dgCMatrix} object or a character representing a filename}
-
-\item{start_iteration}{int or None, optional (default=None)
-Start index of the iteration to predict.
-If None or <= 0, starts from the first iteration.}
-
-\item{num_iteration}{int or None, optional (default=None)
-Limit number of iterations in the prediction.
-If None, if the best iteration exists and start_iteration is None or <= 0, the
-best iteration is used; otherwise, all iterations from start_iteration are used.
-If <= 0, all iterations from start_iteration are used (no limits).}
-
-\item{rawscore}{whether the prediction should be returned in the for of original untransformed
-sum of predictions from boosting iterations' results. E.g., setting \code{rawscore=TRUE}
-for logistic regression would result in predictions for log-odds instead of probabilities.}
-
-\item{predleaf}{whether predict leaf index instead.}
-
-\item{predcontrib}{return per-feature contributions for each record.}
-
-\item{header}{only used for prediction for text file. True if text file has header}
-
-\item{reshape}{whether to reshape the vector of predictions to a matrix form when there are several
-prediction outputs per case.}
-
-\item{...}{Additional named arguments passed to the \code{predict()} method of
-the \code{lgb.Booster} object passed to \code{object}.}
-}
-\value{
-For regression or binary classification, it returns a vector of length \code{nrows(data)}.
-        For multiclass classification, either a \code{num_class * nrows(data)} vector or
-        a \code{(nrows(data), num_class)} dimension matrix is returned, depending on
-        the \code{reshape} value.
-
-        When \code{predleaf = TRUE}, the output is a matrix object with the
-        number of columns corresponding to the number of trees.
-}
-\description{
-Predicted values based on class \code{lgb.Booster}
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-params <- list(objective = "regression", metric = "l2")
-valids <- list(test = dtest)
-model <- lgb.train(
-  params = params
-  , data = dtrain
-  , nrounds = 5L
-  , valids = valids
-  , min_data = 1L
-  , learning_rate = 1.0
-)
-preds <- predict(model, test$data)
-}
-}
diff --git a/R-package/man/readRDS.lgb.Booster.Rd b/R-package/man/readRDS.lgb.Booster.Rd
deleted file mode 100644
index add489441..000000000
--- a/R-package/man/readRDS.lgb.Booster.Rd
+++ /dev/null
@@ -1,44 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/readRDS.lgb.Booster.R
-\name{readRDS.lgb.Booster}
-\alias{readRDS.lgb.Booster}
-\title{readRDS for \code{lgb.Booster} models}
-\usage{
-readRDS.lgb.Booster(file, refhook = NULL)
-}
-\arguments{
-\item{file}{a connection or the name of the file where the R object is saved to or read from.}
-
-\item{refhook}{a hook function for handling reference objects.}
-}
-\value{
-\code{lgb.Booster}
-}
-\description{
-Attempts to load a model stored in a \code{.rds} file, using \code{\link[base]{readRDS}}
-}
-\examples{
-\donttest{
-library(lightgbm)
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-params <- list(objective = "regression", metric = "l2")
-valids <- list(test = dtest)
-model <- lgb.train(
-  params = params
-  , data = dtrain
-  , nrounds = 10L
-  , valids = valids
-  , min_data = 1L
-  , learning_rate = 1.0
-  , early_stopping_rounds = 5L
-)
-model_file <- tempfile(fileext = ".rds")
-saveRDS.lgb.Booster(model, model_file)
-new_model <- readRDS.lgb.Booster(model_file)
-}
-}
diff --git a/R-package/man/saveRDS.lgb.Booster.Rd b/R-package/man/saveRDS.lgb.Booster.Rd
deleted file mode 100644
index 76f1165f8..000000000
--- a/R-package/man/saveRDS.lgb.Booster.Rd
+++ /dev/null
@@ -1,67 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/saveRDS.lgb.Booster.R
-\name{saveRDS.lgb.Booster}
-\alias{saveRDS.lgb.Booster}
-\title{saveRDS for \code{lgb.Booster} models}
-\usage{
-saveRDS.lgb.Booster(
-  object,
-  file,
-  ascii = FALSE,
-  version = NULL,
-  compress = TRUE,
-  refhook = NULL,
-  raw = TRUE
-)
-}
-\arguments{
-\item{object}{\code{lgb.Booster} object to serialize.}
-
-\item{file}{a connection or the name of the file where the R object is saved to or read from.}
-
-\item{ascii}{a logical. If TRUE or NA, an ASCII representation is written; otherwise (default),
-a binary one is used. See the comments in the help for save.}
-
-\item{version}{the workspace format version to use. \code{NULL} specifies the current default
-version (2). Versions prior to 2 are not supported, so this will only be relevant
-when there are later versions.}
-
-\item{compress}{a logical specifying whether saving to a named file is to use "gzip" compression,
-or one of \code{"gzip"}, \code{"bzip2"} or \code{"xz"} to indicate the type of
-compression to be used. Ignored if file is a connection.}
-
-\item{refhook}{a hook function for handling reference objects.}
-
-\item{raw}{whether to save the model in a raw variable or not, recommended to leave it to \code{TRUE}.}
-}
-\value{
-NULL invisibly.
-}
-\description{
-Attempts to save a model using RDS. Has an additional parameter (\code{raw})
-             which decides whether to save the raw model or not.
-}
-\examples{
-\donttest{
-library(lightgbm)
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-data(agaricus.test, package = "lightgbm")
-test <- agaricus.test
-dtest <- lgb.Dataset.create.valid(dtrain, test$data, label = test$label)
-params <- list(objective = "regression", metric = "l2")
-valids <- list(test = dtest)
-model <- lgb.train(
-    params = params
-    , data = dtrain
-    , nrounds = 10L
-    , valids = valids
-    , min_data = 1L
-    , learning_rate = 1.0
-    , early_stopping_rounds = 5L
-)
-model_file <- tempfile(fileext = ".rds")
-saveRDS.lgb.Booster(model, model_file)
-}
-}
diff --git a/R-package/man/setinfo.Rd b/R-package/man/setinfo.Rd
deleted file mode 100644
index e981ed051..000000000
--- a/R-package/man/setinfo.Rd
+++ /dev/null
@@ -1,54 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Dataset.R
-\name{setinfo}
-\alias{setinfo}
-\alias{setinfo.lgb.Dataset}
-\title{Set information of an \code{lgb.Dataset} object}
-\usage{
-setinfo(dataset, ...)
-
-\method{setinfo}{lgb.Dataset}(dataset, name, info, ...)
-}
-\arguments{
-\item{dataset}{Object of class \code{lgb.Dataset}}
-
-\item{...}{other parameters}
-
-\item{name}{the name of the field to get}
-
-\item{info}{the specific field of information to set}
-}
-\value{
-the dataset you passed in
-}
-\description{
-Set one attribute of a \code{lgb.Dataset}
-}
-\details{
-The \code{name} field can be one of the following:
-
-\itemize{
-    \item{\code{label}: vector of labels to use as the target variable}
-    \item{\code{weight}: to do a weight rescale}
-    \item{\code{init_score}: initial score is the base prediction lightgbm will boost from}
-    \item{\code{group}: used for learning-to-rank tasks. An integer vector describing how to
-        group rows together as ordered results from the same set of candidate results to be ranked.
-        For example, if you have a 100-document dataset with \code{group = c(10, 20, 40, 10, 10, 10)},
-        that means that you have 6 groups, where the first 10 records are in the first group,
-        records 11-30 are in the second group, etc.}
-}
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-lgb.Dataset.construct(dtrain)
-
-labels <- lightgbm::getinfo(dtrain, "label")
-lightgbm::setinfo(dtrain, "label", 1 - labels)
-
-labels2 <- lightgbm::getinfo(dtrain, "label")
-stopifnot(all.equal(labels2, 1 - labels))
-}
-}
diff --git a/R-package/man/slice.Rd b/R-package/man/slice.Rd
deleted file mode 100644
index 0e2c73108..000000000
--- a/R-package/man/slice.Rd
+++ /dev/null
@@ -1,36 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lgb.Dataset.R
-\name{slice}
-\alias{slice}
-\alias{slice.lgb.Dataset}
-\title{Slice a dataset}
-\usage{
-slice(dataset, ...)
-
-\method{slice}{lgb.Dataset}(dataset, idxset, ...)
-}
-\arguments{
-\item{dataset}{Object of class \code{lgb.Dataset}}
-
-\item{...}{other parameters (currently not used)}
-
-\item{idxset}{an integer vector of indices of rows needed}
-}
-\value{
-constructed sub dataset
-}
-\description{
-Get a new \code{lgb.Dataset} containing the specified rows of
-             original \code{lgb.Dataset} object
-}
-\examples{
-\donttest{
-data(agaricus.train, package = "lightgbm")
-train <- agaricus.train
-dtrain <- lgb.Dataset(train$data, label = train$label)
-
-dsub <- lightgbm::slice(dtrain, seq_len(42L))
-lgb.Dataset.construct(dsub)
-labels <- lightgbm::getinfo(dsub, "label")
-}
-}
diff --git a/R-package/pkgdown/_pkgdown.yml b/R-package/pkgdown/_pkgdown.yml
deleted file mode 100644
index 60ed132dd..000000000
--- a/R-package/pkgdown/_pkgdown.yml
+++ /dev/null
@@ -1,96 +0,0 @@
-template:
-  params:
-    bootswatch: cerulean
-
-site:
-  root: ''
-  title: LightGBM, Light Gradient Boosting Machine
-
-repo:
-  url:
-    home: https://github.com/microsoft/LightGBM/
-    source: https://github.com/microsoft/LightGBM/tree/master/R-package/
-    issue: https://github.com/microsoft/LightGBM/issues/
-    user: https://github.com/
-
-development:
-  mode: unreleased
-
-authors:
-  Guolin Ke:
-    href: https://github.com/guolinke
-    html: <img src="https://avatars0.githubusercontent.com/u/16040950?s=400&v=4" height="48" /> Guolin Ke
-  Damien Soukhavong:
-    href: https://github.com/Laurae2
-    html: <img src="https://avatars1.githubusercontent.com/u/9083669?s=460&v=4" height="48" /> Damien Soukhavong
-  Yachen Yan:
-    href: https://github.com/yanyachen
-    html: <img src="https://avatars1.githubusercontent.com/u/6893682?s=460&v=4" height="48" /> Yachen Yan
-  James Lamb:
-    href: https://github.com/jameslamb
-    html: <img src="https://avatars1.githubusercontent.com/u/7608904?s=400&v=4" height="48" /> James Lamb
-
-navbar:
-  title: LightGBM
-  type: default
-  left:
-  - icon: fa-reply fa-lg
-    href: ../
-  - icon: fa-home fa-lg
-    href: index.html
-  - text: Reference
-    href: reference/index.html
-  right:
-  - icon: fa-github fa-lg
-    href: https://github.com/microsoft/LightGBM/tree/master/R-package
-
-reference:
-  - title: Datasets
-    desc: Datasets included with the R-package
-    contents:
-    - '`agaricus.train`'
-    - '`agaricus.test`'
-    - '`bank`'
-  - title: Data Input / Output
-    desc: Data I/O required for LightGBM
-    contents:
-    - '`dim.lgb.Dataset`'
-    - '`dimnames.lgb.Dataset`'
-    - '`getinfo`'
-    - '`setinfo`'
-    - '`slice`'
-    - '`lgb.Dataset`'
-    - '`lgb.Dataset.construct`'
-    - '`lgb.Dataset.create.valid`'
-    - '`lgb.Dataset.save`'
-    - '`lgb.Dataset.set.categorical`'
-    - '`lgb.Dataset.set.reference`'
-    - '`lgb.convert_with_rules`'
-  - title: Machine Learning
-    desc: Train models with LightGBM and then use them to make predictions on new data
-    contents:
-    - '`lightgbm`'
-    - '`lgb.train`'
-    - '`predict.lgb.Booster`'
-    - '`lgb.cv`'
-  - title: Saving / Loading Models
-    desc: Save and load LightGBM models
-    contents:
-    - '`lgb.dump`'
-    - '`lgb.save`'
-    - '`lgb.load`'
-    - '`lgb.model.dt.tree`'
-    - '`saveRDS.lgb.Booster`'
-    - '`readRDS.lgb.Booster`'
-  - title: Model Interpretation
-    desc: Analyze your models
-    contents:
-    - '`lgb.get.eval.result`'
-    - '`lgb.importance`'
-    - '`lgb.interprete`'
-    - '`lgb.plot.importance`'
-    - '`lgb.plot.interpretation`'
-  - title: Miscellaneous
-    desc: Ungroupable functions to troubleshoot LightGBM
-    contents:
-    - '`lgb.unloader`'
diff --git a/R-package/pkgdown/favicon/apple-touch-icon-120x120.png b/R-package/pkgdown/favicon/apple-touch-icon-120x120.png
deleted file mode 100644
index 67bafad54..000000000
Binary files a/R-package/pkgdown/favicon/apple-touch-icon-120x120.png and /dev/null differ
diff --git a/R-package/pkgdown/favicon/apple-touch-icon-152x152.png b/R-package/pkgdown/favicon/apple-touch-icon-152x152.png
deleted file mode 100644
index ac348c65f..000000000
Binary files a/R-package/pkgdown/favicon/apple-touch-icon-152x152.png and /dev/null differ
diff --git a/R-package/pkgdown/favicon/apple-touch-icon-180x180.png b/R-package/pkgdown/favicon/apple-touch-icon-180x180.png
deleted file mode 100644
index a3ed94dd4..000000000
Binary files a/R-package/pkgdown/favicon/apple-touch-icon-180x180.png and /dev/null differ
diff --git a/R-package/pkgdown/favicon/apple-touch-icon-60x60.png b/R-package/pkgdown/favicon/apple-touch-icon-60x60.png
deleted file mode 100644
index a84c66005..000000000
Binary files a/R-package/pkgdown/favicon/apple-touch-icon-60x60.png and /dev/null differ
diff --git a/R-package/pkgdown/favicon/apple-touch-icon-76x76.png b/R-package/pkgdown/favicon/apple-touch-icon-76x76.png
deleted file mode 100644
index d7fb51581..000000000
Binary files a/R-package/pkgdown/favicon/apple-touch-icon-76x76.png and /dev/null differ
diff --git a/R-package/pkgdown/favicon/apple-touch-icon.png b/R-package/pkgdown/favicon/apple-touch-icon.png
deleted file mode 100644
index 07f55fa6c..000000000
Binary files a/R-package/pkgdown/favicon/apple-touch-icon.png and /dev/null differ
diff --git a/R-package/pkgdown/favicon/favicon-16x16.png b/R-package/pkgdown/favicon/favicon-16x16.png
deleted file mode 100644
index 05e32106e..000000000
Binary files a/R-package/pkgdown/favicon/favicon-16x16.png and /dev/null differ
diff --git a/R-package/pkgdown/favicon/favicon-32x32.png b/R-package/pkgdown/favicon/favicon-32x32.png
deleted file mode 100644
index 817e0a64c..000000000
Binary files a/R-package/pkgdown/favicon/favicon-32x32.png and /dev/null differ
diff --git a/R-package/pkgdown/favicon/favicon.ico b/R-package/pkgdown/favicon/favicon.ico
deleted file mode 100644
index 4f8cb7e69..000000000
Binary files a/R-package/pkgdown/favicon/favicon.ico and /dev/null differ
diff --git a/R-package/recreate-configure.sh b/R-package/recreate-configure.sh
deleted file mode 100755
index 2df5ffa64..000000000
--- a/R-package/recreate-configure.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/bash
-
-# recreates 'configure' from 'configure.ac'
-# this script should run on Ubuntu 20.04
-AUTOCONF_VERSION=$(cat R-package/AUTOCONF_UBUNTU_VERSION)
-
-# R packages cannot have versions like 3.0.0rc1, but
-# 3.0.0-1 is acceptable
-LGB_VERSION=$(cat VERSION.txt | sed "s/rc/-/g")
-
-# this script changes configure.ac. Copying to a temporary file
-# so changes to configure.ac don't get committed in git
-TMP_CONFIGURE_AC=".configure.ac"
-
-echo "Creating 'configure' script with Autoconf ${AUTOCONF_VERSION}"
-
-apt update
-apt-get install \
-    --no-install-recommends \
-    -y \
-        autoconf=${AUTOCONF_VERSION}
-
-cd R-package
-
-cp configure.ac ${TMP_CONFIGURE_AC}
-sed -i.bak -e "s/~~VERSION~~/${LGB_VERSION}/" ${TMP_CONFIGURE_AC}
-
-autoconf \
-    --output configure \
-    ${TMP_CONFIGURE_AC} \
-    || exit -1
-
-rm ${TMP_CONFIGURE_AC}
-
-rm -r autom4te.cache || echo "no autoconf cache found"
-
-echo "done creating 'configure' script"
diff --git a/R-package/src/Makevars.in b/R-package/src/Makevars.in
deleted file mode 100644
index 2490ba075..000000000
--- a/R-package/src/Makevars.in
+++ /dev/null
@@ -1,56 +0,0 @@
-CXX_STD = CXX11
-
-PKGROOT=.
-
-LGB_CPPFLAGS = \
-    @LGB_CPPFLAGS@ \
-    -DUSE_SOCKET \
-    -DLGB_R_BUILD
-
-PKG_CPPFLAGS = \
-    -I$(PKGROOT)/include \
-    $(LGB_CPPFLAGS)
-
-PKG_CXXFLAGS = \
-    @OPENMP_CXXFLAGS@ \
-    -pthread
-
-PKG_LIBS = \
-    @OPENMP_CXXFLAGS@ \
-    @OPENMP_LIB@ \
-    -pthread
-
-OBJECTS = \
-    boosting/boosting.o \
-    boosting/gbdt.o \
-    boosting/gbdt_model_text.o \
-    boosting/gbdt_prediction.o \
-    boosting/prediction_early_stop.o \
-    io/bin.o \
-    io/config.o \
-    io/config_auto.o \
-    io/dataset.o \
-    io/dataset_loader.o \
-    io/file_io.o \
-    io/json11.o \
-    io/metadata.o \
-    io/parser.o \
-    io/train_share_states.o \
-    io/tree.o \
-    metric/dcg_calculator.o \
-    metric/metric.o \
-    objective/objective_function.o \
-    network/ifaddrs_patch.o \
-    network/linker_topo.o \
-    network/linkers_mpi.o \
-    network/linkers_socket.o \
-    network/network.o \
-    treelearner/data_parallel_tree_learner.o \
-    treelearner/feature_parallel_tree_learner.o \
-    treelearner/gpu_tree_learner.o \
-    treelearner/linear_tree_learner.o \
-    treelearner/serial_tree_learner.o \
-    treelearner/tree_learner.o \
-    treelearner/voting_parallel_tree_learner.o \
-    c_api.o \
-    lightgbm_R.o
diff --git a/R-package/src/Makevars.win.in b/R-package/src/Makevars.win.in
deleted file mode 100644
index 0fb2de926..000000000
--- a/R-package/src/Makevars.win.in
+++ /dev/null
@@ -1,57 +0,0 @@
-CXX_STD = CXX11
-
-PKGROOT=.
-
-LGB_CPPFLAGS = \
-    @LGB_CPPFLAGS@ \
-    -DUSE_SOCKET \
-    -DLGB_R_BUILD
-
-PKG_CPPFLAGS = \
-    -I$(PKGROOT)/include \
-    $(LGB_CPPFLAGS)
-
-PKG_CXXFLAGS = \
-    ${SHLIB_OPENMP_CXXFLAGS} \
-    ${SHLIB_PTHREAD_FLAGS}
-
-PKG_LIBS = \
-    ${SHLIB_OPENMP_CXXFLAGS} \
-    ${SHLIB_PTHREAD_FLAGS} \
-    -lws2_32 \
-    -lIphlpapi
-
-OBJECTS = \
-    boosting/boosting.o \
-    boosting/gbdt.o \
-    boosting/gbdt_model_text.o \
-    boosting/gbdt_prediction.o \
-    boosting/prediction_early_stop.o \
-    io/bin.o \
-    io/config.o \
-    io/config_auto.o \
-    io/dataset.o \
-    io/dataset_loader.o \
-    io/file_io.o \
-    io/json11.o \
-    io/metadata.o \
-    io/parser.o \
-    io/train_share_states.o \
-    io/tree.o \
-    metric/dcg_calculator.o \
-    metric/metric.o \
-    objective/objective_function.o \
-    network/ifaddrs_patch.o \
-    network/linker_topo.o \
-    network/linkers_mpi.o \
-    network/linkers_socket.o \
-    network/network.o \
-    treelearner/data_parallel_tree_learner.o \
-    treelearner/feature_parallel_tree_learner.o \
-    treelearner/gpu_tree_learner.o \
-    treelearner/linear_tree_learner.o \
-    treelearner/serial_tree_learner.o \
-    treelearner/tree_learner.o \
-    treelearner/voting_parallel_tree_learner.o \
-    c_api.o \
-    lightgbm_R.o
diff --git a/R-package/src/R_object_helper.h b/R-package/src/R_object_helper.h
deleted file mode 100644
index b961dc76c..000000000
--- a/R-package/src/R_object_helper.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*!
- * Copyright (c) 2017 Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See LICENSE file in the project root for license information.
- *
- * \brief A simple wrapper for accessing data in R object.
- *
- * \note
- * We previously did not want to use R's headers because of license concerns. This is no longer a concern:
- * https://github.com/microsoft/LightGBM/issues/629#issuecomment-474995635
- * For now, this wrapper is LightGBM's interface from R to C.
- * If R changes the way it defines objects, this file will need to be updated as well.
- */
-#ifndef R_OBJECT_HELPER_H_
-#define R_OBJECT_HELPER_H_
-
-#include <cstdint>
-
-#define NAMED_BITS 16
-struct lgbm_sxpinfo {
-  unsigned int type : 5;
-  unsigned int scalar : 1;
-  unsigned int obj : 1;
-  unsigned int alt : 1;
-  unsigned int gp : 16;
-  unsigned int mark : 1;
-  unsigned int debug : 1;
-  unsigned int trace : 1;
-  unsigned int spare : 1;
-  unsigned int gcgen : 1;
-  unsigned int gccls : 3;
-  unsigned int named : NAMED_BITS;
-  unsigned int extra : 32 - NAMED_BITS;
-};
-
-struct lgbm_primsxp {
-  int offset;
-};
-
-struct lgbm_symsxp {
-  struct LGBM_SER *pname;
-  struct LGBM_SER *value;
-  struct LGBM_SER *internal;
-};
-
-struct lgbm_listsxp {
-  struct LGBM_SER *carval;
-  struct LGBM_SER *cdrval;
-  struct LGBM_SER *tagval;
-};
-
-struct lgbm_envsxp {
-  struct LGBM_SER *frame;
-  struct LGBM_SER *enclos;
-  struct LGBM_SER *hashtab;
-};
-
-struct lgbm_closxp {
-  struct LGBM_SER *formals;
-  struct LGBM_SER *body;
-  struct LGBM_SER *env;
-};
-
-struct lgbm_promsxp {
-  struct LGBM_SER *value;
-  struct LGBM_SER *expr;
-  struct LGBM_SER *env;
-};
-
-typedef struct LGBM_SER {
-  struct lgbm_sxpinfo sxpinfo;
-  struct LGBM_SER* attrib;
-  struct LGBM_SER* gengc_next_node, *gengc_prev_node;
-  union {
-    struct lgbm_primsxp primsxp;
-    struct lgbm_symsxp symsxp;
-    struct lgbm_listsxp listsxp;
-    struct lgbm_envsxp envsxp;
-    struct lgbm_closxp closxp;
-    struct lgbm_promsxp promsxp;
-  } u;
-} LGBM_SER, *LGBM_SE;
-
-struct lgbm_vecsxp {
-  R_xlen_t length;
-  R_xlen_t truelength;
-};
-
-typedef struct VECTOR_SER {
-  struct lgbm_sxpinfo sxpinfo;
-  struct LGBM_SER* attrib;
-  struct LGBM_SER* gengc_next_node, *gengc_prev_node;
-  struct lgbm_vecsxp vecsxp;
-} VECTOR_SER, *VECSE;
-
-typedef union { VECTOR_SER s; double align; } SEXPREC_ALIGN;
-
-#define DATAPTR(x)     ((reinterpret_cast<SEXPREC_ALIGN*>(x)) + 1)
-
-#define R_CHAR_PTR(x)  (reinterpret_cast<char*>DATAPTR(x))
-
-#define R_IS_NULL(x)   ((*reinterpret_cast<LGBM_SE>(x)).sxpinfo.type == 0)
-
-// 64bit pointer
-#if INTPTR_MAX == INT64_MAX
-
-  #define R_ADDR(x)  (reinterpret_cast<int64_t*> DATAPTR(x))
-
-  inline void R_SET_PTR(LGBM_SE x, void* ptr) {
-    if (ptr == nullptr) {
-      R_ADDR(x)[0] = (int64_t)(NULL);
-    } else {
-      R_ADDR(x)[0] = (int64_t)(ptr);
-    }
-  }
-
-  inline void* R_GET_PTR(LGBM_SE x) {
-    if (R_IS_NULL(x)) {
-      return nullptr;
-    } else {
-      auto ret = reinterpret_cast<void*>(R_ADDR(x)[0]);
-      if (ret == NULL) {
-        ret = nullptr;
-      }
-      return ret;
-    }
-  }
-
-#else
-
-  #define R_ADDR(x) (reinterpret_cast<int32_t*> DATAPTR(x))
-
-  inline void R_SET_PTR(LGBM_SE x, void* ptr) {
-    if (ptr == nullptr) {
-      R_ADDR(x)[0] = (int32_t)(NULL);
-    } else {
-      R_ADDR(x)[0] = (int32_t)(ptr);
-    }
-  }
-
-  inline void* R_GET_PTR(LGBM_SE x) {
-    if (R_IS_NULL(x)) {
-      return nullptr;
-    } else {
-      auto ret = reinterpret_cast<void*>(R_ADDR(x)[0]);
-      if (ret == NULL) {
-        ret = nullptr;
-      }
-      return ret;
-    }
-  }
-
-#endif  // INTPTR_MAX == INT64_MAX
-
-#endif  // R_OBJECT_HELPER_H_
diff --git a/R-package/src/install.libs.R b/R-package/src/install.libs.R
deleted file mode 100644
index 9f839e2c1..000000000
--- a/R-package/src/install.libs.R
+++ /dev/null
@@ -1,256 +0,0 @@
-# User options
-use_gpu <- FALSE
-
-# For Windows, the package will be built with Visual Studio
-# unless you set one of these to TRUE
-use_mingw <- FALSE
-use_msys2 <- FALSE
-
-if (use_mingw && use_msys2) {
-  stop("Cannot use both MinGW and MSYS2. Please choose only one.")
-}
-
-if (.Machine$sizeof.pointer != 8L) {
-  stop("LightGBM only supports 64-bit R, please check the version of R and Rtools.")
-}
-
-R_int_UUID <- .Internal(internalsID())
-R_ver <- as.double(R.Version()$major) + as.double(R.Version()$minor) / 10.0
-
-if (!(R_int_UUID == "0310d4b8-ccb1-4bb8-ba94-d36a55f60262"
-    || R_int_UUID == "2fdf6c18-697a-4ba7-b8ef-11c0d92f1327")) {
-  warning("Warning: unmatched R_INTERNALS_UUID, may not run normally.")
-}
-
-# system() will not raise an R exception if the process called
-# fails. Wrapping it here to get that behavior.
-#
-# system() introduces a lot of overhead, at least on Windows,
-# so trying processx if it is available
-.run_shell_command <- function(cmd, args, strict = TRUE) {
-    on_windows <- .Platform$OS.type == "windows"
-    has_processx <- suppressMessages({
-      suppressWarnings({
-        require("processx")  # nolint
-      })
-    })
-    if (has_processx && on_windows) {
-      result <- processx::run(
-        command = cmd
-        , args = args
-        , windows_verbatim_args = TRUE
-        , error_on_status = FALSE
-        , echo = TRUE
-      )
-      exit_code <- result$status
-    } else {
-      if (on_windows) {
-        message(paste0(
-          "Using system() to run shell commands. Installing "
-          , "'processx' with install.packages('processx') might "
-          , "make this faster."
-        ))
-      }
-      cmd <- paste0(cmd, " ", paste0(args, collapse = " "))
-      exit_code <- system(cmd)
-    }
-
-    if (exit_code != 0L && isTRUE(strict)) {
-        stop(paste0("Command failed with exit code: ", exit_code))
-    }
-    return(invisible(exit_code))
-}
-
-# try to generate Visual Studio build files
-.generate_vs_makefiles <- function(cmake_args) {
-  vs_versions <- c(
-    "Visual Studio 16 2019"
-    , "Visual Studio 15 2017"
-    , "Visual Studio 14 2015"
-  )
-  working_vs_version <- NULL
-  for (vs_version in vs_versions) {
-    message(sprintf("Trying '%s'", vs_version))
-    # if the build directory is not empty, clean it
-    if (file.exists("CMakeCache.txt")) {
-      file.remove("CMakeCache.txt")
-    }
-    vs_cmake_args <- c(
-      cmake_args
-      , "-G"
-      , shQuote(vs_version)
-      , "-A"
-      , "x64"
-    )
-    exit_code <- .run_shell_command("cmake", c(vs_cmake_args, ".."), strict = FALSE)
-    if (exit_code == 0L) {
-      message(sprintf("Successfully created build files for '%s'", vs_version))
-      return(invisible(TRUE))
-    }
-
-  }
-  return(invisible(FALSE))
-}
-
-# Move in CMakeLists.txt
-write_succeeded <- file.copy(
-  "../inst/bin/CMakeLists.txt"
-  , "CMakeLists.txt"
-  , overwrite = TRUE
-)
-if (!write_succeeded) {
-  stop("Copying CMakeLists.txt failed")
-}
-
-# Get some paths
-source_dir <- file.path(R_PACKAGE_SOURCE, "src", fsep = "/")
-build_dir <- file.path(source_dir, "build", fsep = "/")
-
-# Prepare building package
-dir.create(
-  build_dir
-  , recursive = TRUE
-  , showWarnings = FALSE
-)
-setwd(build_dir)
-
-use_visual_studio <- !(use_mingw || use_msys2)
-
-# If using MSVC to build, pull in the script used
-# to create R.def from R.dll
-if (WINDOWS && use_visual_studio) {
-  write_succeeded <- file.copy(
-    "../../inst/make-r-def.R"
-    , file.path(build_dir, "make-r-def.R")
-    , overwrite = TRUE
-  )
-  if (!write_succeeded) {
-    stop("Copying make-r-def.R failed")
-  }
-}
-
-# Prepare installation steps
-cmake_args <- NULL
-build_cmd <- "make"
-build_args <- "_lightgbm"
-lib_folder <- file.path(source_dir, fsep = "/")
-
-# add in command-line arguments
-# NOTE: build_r.R replaces the line below
-command_line_args <- NULL
-cmake_args <- c(cmake_args, command_line_args)
-
-WINDOWS_BUILD_TOOLS <- list(
-  "MinGW" = c(
-    build_tool = "mingw32-make.exe"
-    , makefile_generator = "MinGW Makefiles"
-  )
-  , "MSYS2" = c(
-    build_tool = "make.exe"
-    , makefile_generator = "MSYS Makefiles"
-  )
-)
-
-if (use_mingw) {
-  windows_toolchain <- "MinGW"
-} else if (use_msys2) {
-  windows_toolchain <- "MSYS2"
-} else {
-  # Rtools 4.0 moved from MinGW to MSYS toolchain. If user tries
-  # Visual Studio install but that fails, fall back to the toolchain
-  # supported in Rtools
-  if (R_ver >= 4.0) {
-    windows_toolchain <- "MSYS2"
-  } else {
-    windows_toolchain <- "MinGW"
-  }
-}
-windows_build_tool <- WINDOWS_BUILD_TOOLS[[windows_toolchain]][["build_tool"]]
-windows_makefile_generator <- WINDOWS_BUILD_TOOLS[[windows_toolchain]][["makefile_generator"]]
-
-if (use_gpu) {
-  cmake_args <- c(cmake_args, "-DUSE_GPU=ON")
-}
-cmake_args <- c(cmake_args, "-D__BUILD_FOR_R=ON")
-
-# Pass in R version, used to help find R executable for linking
-R_version_string <- paste(
-  R.Version()[["major"]]
-  , R.Version()[["minor"]]
-  , sep = "."
-)
-r_version_arg <- sprintf("-DCMAKE_R_VERSION='%s'", R_version_string)
-cmake_args <- c(cmake_args, r_version_arg)
-
-# the checks below might already run `cmake -G`. If they do, set this flag
-# to TRUE to avoid re-running it later
-makefiles_already_generated <- FALSE
-
-# Check if Windows installation (for gcc vs Visual Studio)
-if (WINDOWS) {
-  if (!use_visual_studio) {
-    message(sprintf("Trying to build with %s", windows_toolchain))
-    # Must build twice for Windows due sh.exe in Rtools
-    cmake_args <- c(cmake_args, "-G", shQuote(windows_makefile_generator))
-    .run_shell_command("cmake", c(cmake_args, ".."), strict = FALSE)
-    build_cmd <- windows_build_tool
-    build_args <- "_lightgbm"
-  } else {
-    visual_studio_succeeded <- .generate_vs_makefiles(cmake_args)
-    if (!isTRUE(visual_studio_succeeded)) {
-      warning(sprintf("Building with Visual Studio failed. Attempting with %s", windows_toolchain))
-      # Must build twice for Windows due sh.exe in Rtools
-      cmake_args <- c(cmake_args, "-G", shQuote(windows_makefile_generator))
-      .run_shell_command("cmake", c(cmake_args, ".."), strict = FALSE)
-      build_cmd <- windows_build_tool
-      build_args <- "_lightgbm"
-    } else {
-      build_cmd <- "cmake"
-      build_args <- c("--build", ".", "--target", "_lightgbm", "--config", "Release")
-      lib_folder <- file.path(source_dir, "Release", fsep = "/")
-      makefiles_already_generated <- TRUE
-    }
-  }
-} else {
-    .run_shell_command("cmake", c(cmake_args, ".."))
-    makefiles_already_generated <- TRUE
-}
-
-# generate build files
-if (!makefiles_already_generated) {
-  .run_shell_command("cmake", c(cmake_args, ".."))
-}
-
-# build the library
-message("Building lib_lightgbm")
-.run_shell_command(build_cmd, build_args)
-src <- file.path(lib_folder, paste0("lib_lightgbm", SHLIB_EXT), fsep = "/")
-
-# Packages with install.libs.R need to copy some artifacts into the
-# expected places in the package structure.
-# see https://cran.r-project.org/doc/manuals/r-devel/R-exts.html#Package-subdirectories,
-# especially the paragraph on install.libs.R
-dest <- file.path(R_PACKAGE_DIR, paste0("libs", R_ARCH), fsep = "/")
-dir.create(dest, recursive = TRUE, showWarnings = FALSE)
-if (file.exists(src)) {
-  message(paste0("Found library file: ", src, " to move to ", dest))
-  file.copy(src, dest, overwrite = TRUE)
-
-  symbols_file <- file.path(source_dir, "symbols.rds")
-  if (file.exists(symbols_file)) {
-    file.copy(symbols_file, dest, overwrite = TRUE)
-  }
-
-} else {
-  stop(paste0("Cannot find lib_lightgbm", SHLIB_EXT))
-}
-
-# clean up the "build" directory
-if (dir.exists(build_dir)) {
-  message("Removing 'build/' directory")
-  unlink(
-    x = build_dir
-    , recursive = TRUE
-    , force = TRUE
-  )
-}
diff --git a/R-package/src/lightgbm_R.cpp b/R-package/src/lightgbm_R.cpp
deleted file mode 100644
index db9307875..000000000
--- a/R-package/src/lightgbm_R.cpp
+++ /dev/null
@@ -1,698 +0,0 @@
-/*!
- * Copyright (c) 2017 Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See LICENSE file in the project root for license information.
- */
-
-#include "lightgbm_R.h"
-
-#include <LightGBM/utils/common.h>
-#include <LightGBM/utils/log.h>
-#include <LightGBM/utils/openmp_wrapper.h>
-#include <LightGBM/utils/text_reader.h>
-
-#include <R_ext/Rdynload.h>
-
-#define R_NO_REMAP
-#define R_USE_C99_IN_CXX
-#include <R_ext/Error.h>
-
-#include <string>
-#include <cstdio>
-#include <cstring>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#define COL_MAJOR (0)
-
-#define R_API_BEGIN() \
-  try {
-#define R_API_END() } \
-  catch(std::exception& ex) { LGBM_SetLastError(ex.what()); return R_NilValue;} \
-  catch(std::string& ex) { LGBM_SetLastError(ex.c_str()); return R_NilValue; } \
-  catch(...) { LGBM_SetLastError("unknown exception"); return R_NilValue;} \
-  return R_NilValue;
-
-#define CHECK_CALL(x) \
-  if ((x) != 0) { \
-    Rf_error(LGBM_GetLastError()); \
-    return R_NilValue; \
-  }
-
-using LightGBM::Common::Join;
-using LightGBM::Common::Split;
-using LightGBM::Log;
-
-LGBM_SE EncodeChar(LGBM_SE dest, const char* src, SEXP buf_len, SEXP actual_len, size_t str_len) {
-  if (str_len > INT32_MAX) {
-    Log::Fatal("Don't support large string in R-package");
-  }
-  INTEGER(actual_len)[0] = static_cast<int>(str_len);
-  if (Rf_asInteger(buf_len) < static_cast<int>(str_len)) {
-    return dest;
-  }
-  auto ptr = R_CHAR_PTR(dest);
-  std::memcpy(ptr, src, str_len);
-  return dest;
-}
-
-SEXP LGBM_GetLastError_R() {
-  SEXP out;
-  out = PROTECT(Rf_allocVector(STRSXP, 1));
-  SET_STRING_ELT(out, 0, Rf_mkChar(LGBM_GetLastError()));
-  UNPROTECT(1);
-  return out;
-}
-
-SEXP LGBM_DatasetCreateFromFile_R(SEXP filename,
-  SEXP parameters,
-  LGBM_SE reference,
-  LGBM_SE out) {
-  R_API_BEGIN();
-  DatasetHandle handle = nullptr;
-  CHECK_CALL(LGBM_DatasetCreateFromFile(CHAR(Rf_asChar(filename)), CHAR(Rf_asChar(parameters)),
-    R_GET_PTR(reference), &handle));
-  R_SET_PTR(out, handle);
-  R_API_END();
-}
-
-SEXP LGBM_DatasetCreateFromCSC_R(SEXP indptr,
-  SEXP indices,
-  SEXP data,
-  SEXP num_indptr,
-  SEXP nelem,
-  SEXP num_row,
-  SEXP parameters,
-  LGBM_SE reference,
-  LGBM_SE out) {
-  R_API_BEGIN();
-  const int* p_indptr = INTEGER(indptr);
-  const int* p_indices = INTEGER(indices);
-  const double* p_data = REAL(data);
-
-  int64_t nindptr = static_cast<int64_t>(Rf_asInteger(num_indptr));
-  int64_t ndata = static_cast<int64_t>(Rf_asInteger(nelem));
-  int64_t nrow = static_cast<int64_t>(Rf_asInteger(num_row));
-  DatasetHandle handle = nullptr;
-  CHECK_CALL(LGBM_DatasetCreateFromCSC(p_indptr, C_API_DTYPE_INT32, p_indices,
-    p_data, C_API_DTYPE_FLOAT64, nindptr, ndata,
-    nrow, CHAR(Rf_asChar(parameters)), R_GET_PTR(reference), &handle));
-  R_SET_PTR(out, handle);
-  R_API_END();
-}
-
-SEXP LGBM_DatasetCreateFromMat_R(SEXP data,
-  SEXP num_row,
-  SEXP num_col,
-  SEXP parameters,
-  LGBM_SE reference,
-  LGBM_SE out) {
-  R_API_BEGIN();
-  int32_t nrow = static_cast<int32_t>(Rf_asInteger(num_row));
-  int32_t ncol = static_cast<int32_t>(Rf_asInteger(num_col));
-  double* p_mat = REAL(data);
-  DatasetHandle handle = nullptr;
-  CHECK_CALL(LGBM_DatasetCreateFromMat(p_mat, C_API_DTYPE_FLOAT64, nrow, ncol, COL_MAJOR,
-    CHAR(Rf_asChar(parameters)), R_GET_PTR(reference), &handle));
-  R_SET_PTR(out, handle);
-  R_API_END();
-}
-
-SEXP LGBM_DatasetGetSubset_R(LGBM_SE handle,
-  SEXP used_row_indices,
-  SEXP len_used_row_indices,
-  SEXP parameters,
-  LGBM_SE out) {
-  R_API_BEGIN();
-  int len = Rf_asInteger(len_used_row_indices);
-  std::vector<int> idxvec(len);
-  // convert from one-based to  zero-based index
-#pragma omp parallel for schedule(static, 512) if (len >= 1024)
-  for (int i = 0; i < len; ++i) {
-    idxvec[i] = INTEGER(used_row_indices)[i] - 1;
-  }
-  DatasetHandle res = nullptr;
-  CHECK_CALL(LGBM_DatasetGetSubset(R_GET_PTR(handle),
-    idxvec.data(), len, CHAR(Rf_asChar(parameters)),
-    &res));
-  R_SET_PTR(out, res);
-  R_API_END();
-}
-
-SEXP LGBM_DatasetSetFeatureNames_R(LGBM_SE handle,
-  SEXP feature_names) {
-  R_API_BEGIN();
-  auto vec_names = Split(CHAR(Rf_asChar(feature_names)), '\t');
-  std::vector<const char*> vec_sptr;
-  int len = static_cast<int>(vec_names.size());
-  for (int i = 0; i < len; ++i) {
-    vec_sptr.push_back(vec_names[i].c_str());
-  }
-  CHECK_CALL(LGBM_DatasetSetFeatureNames(R_GET_PTR(handle),
-    vec_sptr.data(), len));
-  R_API_END();
-}
-
-SEXP LGBM_DatasetGetFeatureNames_R(LGBM_SE handle,
-  SEXP buf_len,
-  SEXP actual_len,
-  LGBM_SE feature_names) {
-  R_API_BEGIN();
-  int len = 0;
-  CHECK_CALL(LGBM_DatasetGetNumFeature(R_GET_PTR(handle), &len));
-  const size_t reserved_string_size = 256;
-  std::vector<std::vector<char>> names(len);
-  std::vector<char*> ptr_names(len);
-  for (int i = 0; i < len; ++i) {
-    names[i].resize(reserved_string_size);
-    ptr_names[i] = names[i].data();
-  }
-  int out_len;
-  size_t required_string_size;
-  CHECK_CALL(
-    LGBM_DatasetGetFeatureNames(
-      R_GET_PTR(handle),
-      len, &out_len,
-      reserved_string_size, &required_string_size,
-      ptr_names.data()));
-  CHECK_EQ(len, out_len);
-  CHECK_GE(reserved_string_size, required_string_size);
-  auto merge_str = Join<char*>(ptr_names, "\t");
-  EncodeChar(feature_names, merge_str.c_str(), buf_len, actual_len, merge_str.size() + 1);
-  R_API_END();
-}
-
-SEXP LGBM_DatasetSaveBinary_R(LGBM_SE handle,
-  SEXP filename) {
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_DatasetSaveBinary(R_GET_PTR(handle),
-    CHAR(Rf_asChar(filename))));
-  R_API_END();
-}
-
-SEXP LGBM_DatasetFree_R(LGBM_SE handle) {
-  R_API_BEGIN();
-  if (R_GET_PTR(handle) != nullptr) {
-    CHECK_CALL(LGBM_DatasetFree(R_GET_PTR(handle)));
-    R_SET_PTR(handle, nullptr);
-  }
-  R_API_END();
-}
-
-SEXP LGBM_DatasetSetField_R(LGBM_SE handle,
-  SEXP field_name,
-  SEXP field_data,
-  SEXP num_element) {
-  R_API_BEGIN();
-  int len = static_cast<int>(Rf_asInteger(num_element));
-  const char* name = CHAR(Rf_asChar(field_name));
-  if (!strcmp("group", name) || !strcmp("query", name)) {
-    std::vector<int32_t> vec(len);
-#pragma omp parallel for schedule(static, 512) if (len >= 1024)
-    for (int i = 0; i < len; ++i) {
-      vec[i] = static_cast<int32_t>(INTEGER(field_data)[i]);
-    }
-    CHECK_CALL(LGBM_DatasetSetField(R_GET_PTR(handle), name, vec.data(), len, C_API_DTYPE_INT32));
-  } else if (!strcmp("init_score", name)) {
-    CHECK_CALL(LGBM_DatasetSetField(R_GET_PTR(handle), name, REAL(field_data), len, C_API_DTYPE_FLOAT64));
-  } else {
-    std::vector<float> vec(len);
-#pragma omp parallel for schedule(static, 512) if (len >= 1024)
-    for (int i = 0; i < len; ++i) {
-      vec[i] = static_cast<float>(REAL(field_data)[i]);
-    }
-    CHECK_CALL(LGBM_DatasetSetField(R_GET_PTR(handle), name, vec.data(), len, C_API_DTYPE_FLOAT32));
-  }
-  R_API_END();
-}
-
-SEXP LGBM_DatasetGetField_R(LGBM_SE handle,
-  SEXP field_name,
-  SEXP field_data) {
-  R_API_BEGIN();
-  const char* name = CHAR(Rf_asChar(field_name));
-  int out_len = 0;
-  int out_type = 0;
-  const void* res;
-  CHECK_CALL(LGBM_DatasetGetField(R_GET_PTR(handle), name, &out_len, &res, &out_type));
-
-  if (!strcmp("group", name) || !strcmp("query", name)) {
-    auto p_data = reinterpret_cast<const int32_t*>(res);
-    // convert from boundaries to size
-#pragma omp parallel for schedule(static, 512) if (out_len >= 1024)
-    for (int i = 0; i < out_len - 1; ++i) {
-      INTEGER(field_data)[i] = p_data[i + 1] - p_data[i];
-    }
-  } else if (!strcmp("init_score", name)) {
-    auto p_data = reinterpret_cast<const double*>(res);
-#pragma omp parallel for schedule(static, 512) if (out_len >= 1024)
-    for (int i = 0; i < out_len; ++i) {
-      REAL(field_data)[i] = p_data[i];
-    }
-  } else {
-    auto p_data = reinterpret_cast<const float*>(res);
-#pragma omp parallel for schedule(static, 512) if (out_len >= 1024)
-    for (int i = 0; i < out_len; ++i) {
-      REAL(field_data)[i] = p_data[i];
-    }
-  }
-  R_API_END();
-}
-
-SEXP LGBM_DatasetGetFieldSize_R(LGBM_SE handle,
-  SEXP field_name,
-  SEXP out) {
-  R_API_BEGIN();
-  const char* name = CHAR(Rf_asChar(field_name));
-  int out_len = 0;
-  int out_type = 0;
-  const void* res;
-  CHECK_CALL(LGBM_DatasetGetField(R_GET_PTR(handle), name, &out_len, &res, &out_type));
-  if (!strcmp("group", name) || !strcmp("query", name)) {
-    out_len -= 1;
-  }
-  INTEGER(out)[0] = static_cast<int>(out_len);
-  R_API_END();
-}
-
-SEXP LGBM_DatasetUpdateParamChecking_R(SEXP old_params,
-  SEXP new_params) {
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_DatasetUpdateParamChecking(CHAR(Rf_asChar(old_params)), CHAR(Rf_asChar(new_params))));
-  R_API_END();
-}
-
-SEXP LGBM_DatasetGetNumData_R(LGBM_SE handle, SEXP out) {
-  int nrow;
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_DatasetGetNumData(R_GET_PTR(handle), &nrow));
-  INTEGER(out)[0] = static_cast<int>(nrow);
-  R_API_END();
-}
-
-SEXP LGBM_DatasetGetNumFeature_R(LGBM_SE handle,
-  SEXP out) {
-  int nfeature;
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_DatasetGetNumFeature(R_GET_PTR(handle), &nfeature));
-  INTEGER(out)[0] = static_cast<int>(nfeature);
-  R_API_END();
-}
-
-// --- start Booster interfaces
-
-SEXP LGBM_BoosterFree_R(LGBM_SE handle) {
-  R_API_BEGIN();
-  if (R_GET_PTR(handle) != nullptr) {
-    CHECK_CALL(LGBM_BoosterFree(R_GET_PTR(handle)));
-    R_SET_PTR(handle, nullptr);
-  }
-  R_API_END();
-}
-
-SEXP LGBM_BoosterCreate_R(LGBM_SE train_data,
-  SEXP parameters,
-  LGBM_SE out) {
-  R_API_BEGIN();
-  BoosterHandle handle = nullptr;
-  CHECK_CALL(LGBM_BoosterCreate(R_GET_PTR(train_data), CHAR(Rf_asChar(parameters)), &handle));
-  R_SET_PTR(out, handle);
-  R_API_END();
-}
-
-SEXP LGBM_BoosterCreateFromModelfile_R(SEXP filename,
-  LGBM_SE out) {
-  R_API_BEGIN();
-  int out_num_iterations = 0;
-  BoosterHandle handle = nullptr;
-  CHECK_CALL(LGBM_BoosterCreateFromModelfile(CHAR(Rf_asChar(filename)), &out_num_iterations, &handle));
-  R_SET_PTR(out, handle);
-  R_API_END();
-}
-
-SEXP LGBM_BoosterLoadModelFromString_R(SEXP model_str,
-  LGBM_SE out) {
-  R_API_BEGIN();
-  int out_num_iterations = 0;
-  BoosterHandle handle = nullptr;
-  CHECK_CALL(LGBM_BoosterLoadModelFromString(CHAR(Rf_asChar(model_str)), &out_num_iterations, &handle));
-  R_SET_PTR(out, handle);
-  R_API_END();
-}
-
-SEXP LGBM_BoosterMerge_R(LGBM_SE handle,
-  LGBM_SE other_handle) {
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_BoosterMerge(R_GET_PTR(handle), R_GET_PTR(other_handle)));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterAddValidData_R(LGBM_SE handle,
-  LGBM_SE valid_data) {
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_BoosterAddValidData(R_GET_PTR(handle), R_GET_PTR(valid_data)));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterResetTrainingData_R(LGBM_SE handle,
-  LGBM_SE train_data) {
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_BoosterResetTrainingData(R_GET_PTR(handle), R_GET_PTR(train_data)));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterResetParameter_R(LGBM_SE handle,
-  SEXP parameters) {
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_BoosterResetParameter(R_GET_PTR(handle), CHAR(Rf_asChar(parameters))));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterGetNumClasses_R(LGBM_SE handle,
-  SEXP out) {
-  int num_class;
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_BoosterGetNumClasses(R_GET_PTR(handle), &num_class));
-  INTEGER(out)[0] = static_cast<int>(num_class);
-  R_API_END();
-}
-
-SEXP LGBM_BoosterUpdateOneIter_R(LGBM_SE handle) {
-  int is_finished = 0;
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_BoosterUpdateOneIter(R_GET_PTR(handle), &is_finished));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterUpdateOneIterCustom_R(LGBM_SE handle,
-  SEXP grad,
-  SEXP hess,
-  SEXP len) {
-  int is_finished = 0;
-  R_API_BEGIN();
-  int int_len = Rf_asInteger(len);
-  std::vector<float> tgrad(int_len), thess(int_len);
-#pragma omp parallel for schedule(static, 512) if (int_len >= 1024)
-  for (int j = 0; j < int_len; ++j) {
-    tgrad[j] = static_cast<float>(REAL(grad)[j]);
-    thess[j] = static_cast<float>(REAL(hess)[j]);
-  }
-  CHECK_CALL(LGBM_BoosterUpdateOneIterCustom(R_GET_PTR(handle), tgrad.data(), thess.data(), &is_finished));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterRollbackOneIter_R(LGBM_SE handle) {
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_BoosterRollbackOneIter(R_GET_PTR(handle)));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterGetCurrentIteration_R(LGBM_SE handle,
-  SEXP out) {
-  int out_iteration;
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_BoosterGetCurrentIteration(R_GET_PTR(handle), &out_iteration));
-  INTEGER(out)[0] = static_cast<int>(out_iteration);
-  R_API_END();
-}
-
-SEXP LGBM_BoosterGetUpperBoundValue_R(LGBM_SE handle,
-  SEXP out_result) {
-  R_API_BEGIN();
-  double* ptr_ret = REAL(out_result);
-  CHECK_CALL(LGBM_BoosterGetUpperBoundValue(R_GET_PTR(handle), ptr_ret));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterGetLowerBoundValue_R(LGBM_SE handle,
-  SEXP out_result) {
-  R_API_BEGIN();
-  double* ptr_ret = REAL(out_result);
-  CHECK_CALL(LGBM_BoosterGetLowerBoundValue(R_GET_PTR(handle), ptr_ret));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterGetEvalNames_R(LGBM_SE handle,
-  SEXP buf_len,
-  SEXP actual_len,
-  LGBM_SE eval_names) {
-  R_API_BEGIN();
-  int len;
-  CHECK_CALL(LGBM_BoosterGetEvalCounts(R_GET_PTR(handle), &len));
-
-  const size_t reserved_string_size = 128;
-  std::vector<std::vector<char>> names(len);
-  std::vector<char*> ptr_names(len);
-  for (int i = 0; i < len; ++i) {
-    names[i].resize(reserved_string_size);
-    ptr_names[i] = names[i].data();
-  }
-
-  int out_len;
-  size_t required_string_size;
-  CHECK_CALL(
-    LGBM_BoosterGetEvalNames(
-      R_GET_PTR(handle),
-      len, &out_len,
-      reserved_string_size, &required_string_size,
-      ptr_names.data()));
-  CHECK_EQ(out_len, len);
-  CHECK_GE(reserved_string_size, required_string_size);
-  auto merge_names = Join<char*>(ptr_names, "\t");
-  EncodeChar(eval_names, merge_names.c_str(), buf_len, actual_len, merge_names.size() + 1);
-  R_API_END();
-}
-
-SEXP LGBM_BoosterGetEval_R(LGBM_SE handle,
-  SEXP data_idx,
-  SEXP out_result) {
-  R_API_BEGIN();
-  int len;
-  CHECK_CALL(LGBM_BoosterGetEvalCounts(R_GET_PTR(handle), &len));
-  double* ptr_ret = REAL(out_result);
-  int out_len;
-  CHECK_CALL(LGBM_BoosterGetEval(R_GET_PTR(handle), Rf_asInteger(data_idx), &out_len, ptr_ret));
-  CHECK_EQ(out_len, len);
-  R_API_END();
-}
-
-SEXP LGBM_BoosterGetNumPredict_R(LGBM_SE handle,
-  SEXP data_idx,
-  SEXP out) {
-  R_API_BEGIN();
-  int64_t len;
-  CHECK_CALL(LGBM_BoosterGetNumPredict(R_GET_PTR(handle), Rf_asInteger(data_idx), &len));
-  INTEGER(out)[0] = static_cast<int>(len);
-  R_API_END();
-}
-
-SEXP LGBM_BoosterGetPredict_R(LGBM_SE handle,
-  SEXP data_idx,
-  SEXP out_result) {
-  R_API_BEGIN();
-  double* ptr_ret = REAL(out_result);
-  int64_t out_len;
-  CHECK_CALL(LGBM_BoosterGetPredict(R_GET_PTR(handle), Rf_asInteger(data_idx), &out_len, ptr_ret));
-  R_API_END();
-}
-
-int GetPredictType(SEXP is_rawscore, SEXP is_leafidx, SEXP is_predcontrib) {
-  int pred_type = C_API_PREDICT_NORMAL;
-  if (Rf_asInteger(is_rawscore)) {
-    pred_type = C_API_PREDICT_RAW_SCORE;
-  }
-  if (Rf_asInteger(is_leafidx)) {
-    pred_type = C_API_PREDICT_LEAF_INDEX;
-  }
-  if (Rf_asInteger(is_predcontrib)) {
-    pred_type = C_API_PREDICT_CONTRIB;
-  }
-  return pred_type;
-}
-
-SEXP LGBM_BoosterPredictForFile_R(LGBM_SE handle,
-  SEXP data_filename,
-  SEXP data_has_header,
-  SEXP is_rawscore,
-  SEXP is_leafidx,
-  SEXP is_predcontrib,
-  SEXP start_iteration,
-  SEXP num_iteration,
-  SEXP parameter,
-  SEXP result_filename) {
-  R_API_BEGIN();
-  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
-  CHECK_CALL(LGBM_BoosterPredictForFile(R_GET_PTR(handle), CHAR(Rf_asChar(data_filename)),
-    Rf_asInteger(data_has_header), pred_type, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration), CHAR(Rf_asChar(parameter)),
-    CHAR(Rf_asChar(result_filename))));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterCalcNumPredict_R(LGBM_SE handle,
-  SEXP num_row,
-  SEXP is_rawscore,
-  SEXP is_leafidx,
-  SEXP is_predcontrib,
-  SEXP start_iteration,
-  SEXP num_iteration,
-  SEXP out_len) {
-  R_API_BEGIN();
-  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
-  int64_t len = 0;
-  CHECK_CALL(LGBM_BoosterCalcNumPredict(R_GET_PTR(handle), Rf_asInteger(num_row),
-    pred_type, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration), &len));
-  INTEGER(out_len)[0] = static_cast<int>(len);
-  R_API_END();
-}
-
-SEXP LGBM_BoosterPredictForCSC_R(LGBM_SE handle,
-  SEXP indptr,
-  SEXP indices,
-  SEXP data,
-  SEXP num_indptr,
-  SEXP nelem,
-  SEXP num_row,
-  SEXP is_rawscore,
-  SEXP is_leafidx,
-  SEXP is_predcontrib,
-  SEXP start_iteration,
-  SEXP num_iteration,
-  SEXP parameter,
-  SEXP out_result) {
-  R_API_BEGIN();
-  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
-
-  const int* p_indptr = INTEGER(indptr);
-  const int* p_indices = INTEGER(indices);
-  const double* p_data = REAL(data);
-
-  int64_t nindptr = Rf_asInteger(num_indptr);
-  int64_t ndata = Rf_asInteger(nelem);
-  int64_t nrow = Rf_asInteger(num_row);
-  double* ptr_ret = REAL(out_result);
-  int64_t out_len;
-  CHECK_CALL(LGBM_BoosterPredictForCSC(R_GET_PTR(handle),
-    p_indptr, C_API_DTYPE_INT32, p_indices,
-    p_data, C_API_DTYPE_FLOAT64, nindptr, ndata,
-    nrow, pred_type,  Rf_asInteger(start_iteration), Rf_asInteger(num_iteration), CHAR(Rf_asChar(parameter)), &out_len, ptr_ret));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterPredictForMat_R(LGBM_SE handle,
-  SEXP data,
-  SEXP num_row,
-  SEXP num_col,
-  SEXP is_rawscore,
-  SEXP is_leafidx,
-  SEXP is_predcontrib,
-  SEXP start_iteration,
-  SEXP num_iteration,
-  SEXP parameter,
-  SEXP out_result) {
-  R_API_BEGIN();
-  int pred_type = GetPredictType(is_rawscore, is_leafidx, is_predcontrib);
-
-  int32_t nrow = Rf_asInteger(num_row);
-  int32_t ncol = Rf_asInteger(num_col);
-
-  const double* p_mat = REAL(data);
-  double* ptr_ret = REAL(out_result);
-  int64_t out_len;
-  CHECK_CALL(LGBM_BoosterPredictForMat(R_GET_PTR(handle),
-    p_mat, C_API_DTYPE_FLOAT64, nrow, ncol, COL_MAJOR,
-    pred_type, Rf_asInteger(start_iteration), Rf_asInteger(num_iteration), CHAR(Rf_asChar(parameter)), &out_len, ptr_ret));
-
-  R_API_END();
-}
-
-SEXP LGBM_BoosterSaveModel_R(LGBM_SE handle,
-  SEXP num_iteration,
-  SEXP feature_importance_type,
-  SEXP filename) {
-  R_API_BEGIN();
-  CHECK_CALL(LGBM_BoosterSaveModel(R_GET_PTR(handle), 0, Rf_asInteger(num_iteration), Rf_asInteger(feature_importance_type), CHAR(Rf_asChar(filename))));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterSaveModelToString_R(LGBM_SE handle,
-  SEXP num_iteration,
-  SEXP feature_importance_type,
-  SEXP buffer_len,
-  SEXP actual_len,
-  LGBM_SE out_str) {
-  R_API_BEGIN();
-  int64_t out_len = 0;
-  int64_t buf_len = static_cast<int64_t>(Rf_asInteger(buffer_len));
-  std::vector<char> inner_char_buf(buf_len);
-  CHECK_CALL(LGBM_BoosterSaveModelToString(R_GET_PTR(handle), 0, Rf_asInteger(num_iteration), Rf_asInteger(feature_importance_type), buf_len, &out_len, inner_char_buf.data()));
-  EncodeChar(out_str, inner_char_buf.data(), buffer_len, actual_len, static_cast<size_t>(out_len));
-  R_API_END();
-}
-
-SEXP LGBM_BoosterDumpModel_R(LGBM_SE handle,
-  SEXP num_iteration,
-  SEXP feature_importance_type,
-  SEXP buffer_len,
-  SEXP actual_len,
-  LGBM_SE out_str) {
-  R_API_BEGIN();
-  int64_t out_len = 0;
-  int64_t buf_len = static_cast<int64_t>(Rf_asInteger(buffer_len));
-  std::vector<char> inner_char_buf(buf_len);
-  CHECK_CALL(LGBM_BoosterDumpModel(R_GET_PTR(handle), 0, Rf_asInteger(num_iteration), Rf_asInteger(feature_importance_type), buf_len, &out_len, inner_char_buf.data()));
-  EncodeChar(out_str, inner_char_buf.data(), buffer_len, actual_len, static_cast<size_t>(out_len));
-  R_API_END();
-}
-
-// .Call() calls
-static const R_CallMethodDef CallEntries[] = {
-  {"LGBM_GetLastError_R"              , (DL_FUNC) &LGBM_GetLastError_R              , 0},
-  {"LGBM_DatasetCreateFromFile_R"     , (DL_FUNC) &LGBM_DatasetCreateFromFile_R     , 4},
-  {"LGBM_DatasetCreateFromCSC_R"      , (DL_FUNC) &LGBM_DatasetCreateFromCSC_R      , 9},
-  {"LGBM_DatasetCreateFromMat_R"      , (DL_FUNC) &LGBM_DatasetCreateFromMat_R      , 6},
-  {"LGBM_DatasetGetSubset_R"          , (DL_FUNC) &LGBM_DatasetGetSubset_R          , 5},
-  {"LGBM_DatasetSetFeatureNames_R"    , (DL_FUNC) &LGBM_DatasetSetFeatureNames_R    , 2},
-  {"LGBM_DatasetGetFeatureNames_R"    , (DL_FUNC) &LGBM_DatasetGetFeatureNames_R    , 4},
-  {"LGBM_DatasetSaveBinary_R"         , (DL_FUNC) &LGBM_DatasetSaveBinary_R         , 2},
-  {"LGBM_DatasetFree_R"               , (DL_FUNC) &LGBM_DatasetFree_R               , 1},
-  {"LGBM_DatasetSetField_R"           , (DL_FUNC) &LGBM_DatasetSetField_R           , 4},
-  {"LGBM_DatasetGetFieldSize_R"       , (DL_FUNC) &LGBM_DatasetGetFieldSize_R       , 3},
-  {"LGBM_DatasetGetField_R"           , (DL_FUNC) &LGBM_DatasetGetField_R           , 3},
-  {"LGBM_DatasetUpdateParamChecking_R", (DL_FUNC) &LGBM_DatasetUpdateParamChecking_R, 2},
-  {"LGBM_DatasetGetNumData_R"         , (DL_FUNC) &LGBM_DatasetGetNumData_R         , 2},
-  {"LGBM_DatasetGetNumFeature_R"      , (DL_FUNC) &LGBM_DatasetGetNumFeature_R      , 2},
-  {"LGBM_BoosterCreate_R"             , (DL_FUNC) &LGBM_BoosterCreate_R             , 3},
-  {"LGBM_BoosterFree_R"               , (DL_FUNC) &LGBM_BoosterFree_R               , 1},
-  {"LGBM_BoosterCreateFromModelfile_R", (DL_FUNC) &LGBM_BoosterCreateFromModelfile_R, 2},
-  {"LGBM_BoosterLoadModelFromString_R", (DL_FUNC) &LGBM_BoosterLoadModelFromString_R, 2},
-  {"LGBM_BoosterMerge_R"              , (DL_FUNC) &LGBM_BoosterMerge_R              , 2},
-  {"LGBM_BoosterAddValidData_R"       , (DL_FUNC) &LGBM_BoosterAddValidData_R       , 2},
-  {"LGBM_BoosterResetTrainingData_R"  , (DL_FUNC) &LGBM_BoosterResetTrainingData_R  , 2},
-  {"LGBM_BoosterResetParameter_R"     , (DL_FUNC) &LGBM_BoosterResetParameter_R     , 2},
-  {"LGBM_BoosterGetNumClasses_R"      , (DL_FUNC) &LGBM_BoosterGetNumClasses_R      , 2},
-  {"LGBM_BoosterUpdateOneIter_R"      , (DL_FUNC) &LGBM_BoosterUpdateOneIter_R      , 1},
-  {"LGBM_BoosterUpdateOneIterCustom_R", (DL_FUNC) &LGBM_BoosterUpdateOneIterCustom_R, 4},
-  {"LGBM_BoosterRollbackOneIter_R"    , (DL_FUNC) &LGBM_BoosterRollbackOneIter_R    , 1},
-  {"LGBM_BoosterGetCurrentIteration_R", (DL_FUNC) &LGBM_BoosterGetCurrentIteration_R, 2},
-  {"LGBM_BoosterGetUpperBoundValue_R" , (DL_FUNC) &LGBM_BoosterGetUpperBoundValue_R , 2},
-  {"LGBM_BoosterGetLowerBoundValue_R" , (DL_FUNC) &LGBM_BoosterGetLowerBoundValue_R , 2},
-  {"LGBM_BoosterGetEvalNames_R"       , (DL_FUNC) &LGBM_BoosterGetEvalNames_R       , 4},
-  {"LGBM_BoosterGetEval_R"            , (DL_FUNC) &LGBM_BoosterGetEval_R            , 3},
-  {"LGBM_BoosterGetNumPredict_R"      , (DL_FUNC) &LGBM_BoosterGetNumPredict_R      , 3},
-  {"LGBM_BoosterGetPredict_R"         , (DL_FUNC) &LGBM_BoosterGetPredict_R         , 3},
-  {"LGBM_BoosterPredictForFile_R"     , (DL_FUNC) &LGBM_BoosterPredictForFile_R     , 10},
-  {"LGBM_BoosterCalcNumPredict_R"     , (DL_FUNC) &LGBM_BoosterCalcNumPredict_R     , 8},
-  {"LGBM_BoosterPredictForCSC_R"      , (DL_FUNC) &LGBM_BoosterPredictForCSC_R      , 14},
-  {"LGBM_BoosterPredictForMat_R"      , (DL_FUNC) &LGBM_BoosterPredictForMat_R      , 11},
-  {"LGBM_BoosterSaveModel_R"          , (DL_FUNC) &LGBM_BoosterSaveModel_R          , 4},
-  {"LGBM_BoosterSaveModelToString_R"  , (DL_FUNC) &LGBM_BoosterSaveModelToString_R  , 6},
-  {"LGBM_BoosterDumpModel_R"          , (DL_FUNC) &LGBM_BoosterDumpModel_R          , 6},
-  {NULL, NULL, 0}
-};
-
-LIGHTGBM_C_EXPORT void R_init_lightgbm(DllInfo *dll);
-
-void R_init_lightgbm(DllInfo *dll) {
-  R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
-  R_useDynamicSymbols(dll, FALSE);
-}
diff --git a/R-package/src/lightgbm_R.h b/R-package/src/lightgbm_R.h
deleted file mode 100644
index 3b46f6e17..000000000
--- a/R-package/src/lightgbm_R.h
+++ /dev/null
@@ -1,597 +0,0 @@
-/*!
- * Copyright (c) 2017 Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See LICENSE file in the project root for license information.
- */
-#ifndef LIGHTGBM_R_H_
-#define LIGHTGBM_R_H_
-
-#include <LightGBM/c_api.h>
-
-#define R_NO_REMAP
-#define R_USE_C99_IN_CXX
-#include <Rinternals.h>
-
-#include "R_object_helper.h"
-
-/*!
-* \brief get string message of the last error
-*  all functions in this file will return 0 on success
-*  and -1 when an error occurred
-* \return err_msg error information
-* \return error information
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_GetLastError_R();
-
-// --- start Dataset interface
-
-/*!
-* \brief load data set from file like the command_line LightGBM does
-* \param filename the name of the file
-* \param parameters additional parameters
-* \param reference used to align bin mapper with other dataset, nullptr means not used
-* \param out created dataset
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetCreateFromFile_R(
-  SEXP filename,
-  SEXP parameters,
-  LGBM_SE reference,
-  LGBM_SE out
-);
-
-/*!
-* \brief create a dataset from CSC format
-* \param indptr pointer to row headers
-* \param indices findex
-* \param data fvalue
-* \param num_indptr number of cols in the matrix + 1
-* \param nelem number of nonzero elements in the matrix
-* \param num_row number of rows
-* \param parameters additional parameters
-* \param reference used to align bin mapper with other dataset, nullptr means not used
-* \param out created dataset
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetCreateFromCSC_R(
-  SEXP indptr,
-  SEXP indices,
-  SEXP data,
-  SEXP num_indptr,
-  SEXP nelem,
-  SEXP num_row,
-  SEXP parameters,
-  LGBM_SE reference,
-  LGBM_SE out
-);
-
-/*!
-* \brief create dataset from dense matrix
-* \param data matric data
-* \param num_row number of rows
-* \param num_col number columns
-* \param parameters additional parameters
-* \param reference used to align bin mapper with other dataset, nullptr means not used
-* \param out created dataset
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetCreateFromMat_R(
-  SEXP data,
-  SEXP num_row,
-  SEXP num_col,
-  SEXP parameters,
-  LGBM_SE reference,
-  LGBM_SE out
-);
-
-/*!
-* \brief Create subset of a data
-* \param handle handle of full dataset
-* \param used_row_indices Indices used in subset
-* \param len_used_row_indices length of Indices used in subset
-* \param parameters additional parameters
-* \param out created dataset
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetGetSubset_R(
-  LGBM_SE handle,
-  SEXP used_row_indices,
-  SEXP len_used_row_indices,
-  SEXP parameters,
-  LGBM_SE out
-);
-
-/*!
-* \brief save feature names to Dataset
-* \param handle handle
-* \param feature_names feature names
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetSetFeatureNames_R(
-  LGBM_SE handle,
-  SEXP feature_names
-);
-
-/*!
-* \brief save feature names to Dataset
-* \param handle handle
-* \param feature_names feature names
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetGetFeatureNames_R(
-  LGBM_SE handle,
-  SEXP buf_len,
-  SEXP actual_len,
-  LGBM_SE feature_names
-);
-
-/*!
-* \brief save dataset to binary file
-* \param handle an instance of dataset
-* \param filename file name
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetSaveBinary_R(
-  LGBM_SE handle,
-  SEXP filename
-);
-
-/*!
-* \brief free dataset
-* \param handle an instance of dataset
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetFree_R(
-  LGBM_SE handle
-);
-
-/*!
-* \brief set vector to a content in info
-*        Note: group and group_id only work for C_API_DTYPE_INT32
-*              label and weight only work for C_API_DTYPE_FLOAT32
-* \param handle an instance of dataset
-* \param field_name field name, can be label, weight, group, group_id
-* \param field_data pointer to vector
-* \param num_element number of element in field_data
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetSetField_R(
-  LGBM_SE handle,
-  SEXP field_name,
-  SEXP field_data,
-  SEXP num_element
-);
-
-/*!
-* \brief get size of info vector from dataset
-* \param handle an instance of dataset
-* \param field_name field name
-* \param out size of info vector from dataset
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetGetFieldSize_R(
-  LGBM_SE handle,
-  SEXP field_name,
-  SEXP out
-);
-
-/*!
-* \brief get info vector from dataset
-* \param handle an instance of dataset
-* \param field_name field name
-* \param field_data pointer to vector
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetGetField_R(
-  LGBM_SE handle,
-  SEXP field_name,
-  SEXP field_data
-);
-
-/*!
- * \brief Raise errors for attempts to update dataset parameters
- * \param old_params Current dataset parameters
- * \param new_params New dataset parameters
- * \return 0 when succeed, -1 when failure happens
- */
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetUpdateParamChecking_R(
-  SEXP old_params,
-  SEXP new_params
-);
-
-/*!
-* \brief get number of data.
-* \param handle the handle to the dataset
-* \param out The address to hold number of data
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetGetNumData_R(
-  LGBM_SE handle,
-  SEXP out
-);
-
-/*!
-* \brief get number of features
-* \param handle the handle to the dataset
-* \param out The output of number of features
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_DatasetGetNumFeature_R(
-  LGBM_SE handle,
-  SEXP out
-);
-
-// --- start Booster interfaces
-
-/*!
-* \brief create a new boosting learner
-* \param train_data training data set
-* \param parameters format: 'key1=value1 key2=value2'
-* \param out handle of created Booster
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterCreate_R(
-  LGBM_SE train_data,
-  SEXP parameters,
-  LGBM_SE out
-);
-
-/*!
-* \brief free obj in handle
-* \param handle handle to be freed
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterFree_R(
-  LGBM_SE handle
-);
-
-/*!
-* \brief load an existing boosting from model file
-* \param filename filename of model
-* \param out handle of created Booster
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterCreateFromModelfile_R(
-  SEXP filename,
-  LGBM_SE out
-);
-
-/*!
-* \brief load an existing boosting from model_str
-* \param model_str string containing the model
-* \param out handle of created Booster
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterLoadModelFromString_R(
-  SEXP model_str,
-  LGBM_SE out
-);
-
-/*!
-* \brief Merge model in two boosters to first handle
-* \param handle handle, will merge other handle to this
-* \param other_handle
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterMerge_R(
-  LGBM_SE handle,
-  LGBM_SE other_handle
-);
-
-/*!
-* \brief Add new validation to booster
-* \param handle handle
-* \param valid_data validation data set
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterAddValidData_R(
-  LGBM_SE handle,
-  LGBM_SE valid_data
-);
-
-/*!
-* \brief Reset training data for booster
-* \param handle handle
-* \param train_data training data set
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterResetTrainingData_R(
-  LGBM_SE handle,
-  LGBM_SE train_data
-);
-
-/*!
-* \brief Reset config for current booster
-* \param handle handle
-* \param parameters format: 'key1=value1 key2=value2'
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterResetParameter_R(
-  LGBM_SE handle,
-  SEXP parameters
-);
-
-/*!
-* \brief Get number of classes
-* \param handle handle
-* \param out number of classes
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetNumClasses_R(
-  LGBM_SE handle,
-  SEXP out
-);
-
-/*!
-* \brief update the model in one round
-* \param handle handle
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterUpdateOneIter_R(
-  LGBM_SE handle
-);
-
-/*!
-* \brief update the model, by directly specify gradient and second order gradient,
-*       this can be used to support customized loss function
-* \param handle handle
-* \param grad gradient statistics
-* \param hess second order gradient statistics
-* \param len length of grad/hess
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterUpdateOneIterCustom_R(
-  LGBM_SE handle,
-  SEXP grad,
-  SEXP hess,
-  SEXP len
-);
-
-/*!
-* \brief Rollback one iteration
-* \param handle handle
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterRollbackOneIter_R(
-  LGBM_SE handle
-);
-
-/*!
-* \brief Get iteration of current boosting rounds
-* \param out iteration of boosting rounds
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetCurrentIteration_R(
-  LGBM_SE handle,
-  SEXP out
-);
-
-/*!
-* \brief Get model upper bound value.
-* \param handle Handle of booster
-* \param[out] out_results Result pointing to max value
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetUpperBoundValue_R(
-    LGBM_SE handle,
-    SEXP out_result
-);
-
-/*!
-* \brief Get model lower bound value.
-* \param handle Handle of booster
-* \param[out] out_results Result pointing to min value
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetLowerBoundValue_R(
-    LGBM_SE handle,
-    SEXP out_result
-);
-
-/*!
-* \brief Get Name of eval
-* \param eval_names eval names
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetEvalNames_R(
-  LGBM_SE handle,
-  SEXP buf_len,
-  SEXP actual_len,
-  LGBM_SE eval_names
-);
-
-/*!
-* \brief get evaluation for training data and validation data
-* \param handle handle
-* \param data_idx 0:training data, 1: 1st valid data, 2:2nd valid data ...
-* \param out_result float array contains result
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetEval_R(
-  LGBM_SE handle,
-  SEXP data_idx,
-  SEXP out_result
-);
-
-/*!
-* \brief Get number of prediction for training data and validation data
-* \param handle handle
-* \param data_idx 0:training data, 1: 1st valid data, 2:2nd valid data ...
-* \param out size of predict
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetNumPredict_R(
-  LGBM_SE handle,
-  SEXP data_idx,
-  SEXP out
-);
-
-/*!
-* \brief Get prediction for training data and validation data.
-*        This can be used to support customized eval function
-* \param handle handle
-* \param data_idx 0:training data, 1: 1st valid data, 2:2nd valid data ...
-* \param out_result, used to store predict result, should pre-allocate memory
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterGetPredict_R(
-  LGBM_SE handle,
-  SEXP data_idx,
-  SEXP out_result
-);
-
-/*!
-* \brief make prediction for file
-* \param handle handle
-* \param data_filename filename of data file
-* \param data_has_header data file has header or not
-* \param is_rawscore
-* \param is_leafidx
-* \param num_iteration number of iteration for prediction, <= 0 means no limit
-* \return 0 when succeed, -1 when failure happens
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterPredictForFile_R(
-  LGBM_SE handle,
-  SEXP data_filename,
-  SEXP data_has_header,
-  SEXP is_rawscore,
-  SEXP is_leafidx,
-  SEXP is_predcontrib,
-  SEXP start_iteration,
-  SEXP num_iteration,
-  SEXP parameter,
-  SEXP result_filename
-);
-
-/*!
-* \brief Get number of prediction
-* \param handle handle
-* \param num_row
-* \param is_rawscore
-* \param is_leafidx
-* \param num_iteration number of iteration for prediction, <= 0 means no limit
-* \param out_len length of prediction
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterCalcNumPredict_R(
-  LGBM_SE handle,
-  SEXP num_row,
-  SEXP is_rawscore,
-  SEXP is_leafidx,
-  SEXP is_predcontrib,
-  SEXP start_iteration,
-  SEXP num_iteration,
-  SEXP out_len
-);
-
-/*!
-* \brief make prediction for a new data set
-*        Note:  should pre-allocate memory for out_result,
-*               for normal and raw score: its length is equal to num_class * num_data
-*               for leaf index, its length is equal to num_class * num_data * num_iteration
-* \param handle handle
-* \param indptr pointer to row headers
-* \param indices findex
-* \param data fvalue
-* \param num_indptr number of cols in the matrix + 1
-* \param nelem number of non-zero elements in the matrix
-* \param num_row number of rows
-* \param is_rawscore
-* \param is_leafidx
-* \param num_iteration number of iteration for prediction, <= 0 means no limit
-* \param out prediction result
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterPredictForCSC_R(
-  LGBM_SE handle,
-  SEXP indptr,
-  SEXP indices,
-  SEXP data,
-  SEXP num_indptr,
-  SEXP nelem,
-  SEXP num_row,
-  SEXP is_rawscore,
-  SEXP is_leafidx,
-  SEXP is_predcontrib,
-  SEXP start_iteration,
-  SEXP num_iteration,
-  SEXP parameter,
-  SEXP out_result
-);
-
-/*!
-* \brief make prediction for a new data set
-*        Note:  should pre-allocate memory for out_result,
-*               for normal and raw score: its length is equal to num_class * num_data
-*               for leaf index, its length is equal to num_class * num_data * num_iteration
-* \param handle handle
-* \param data pointer to the data space
-* \param num_row number of rows
-* \param num_col number columns
-* \param is_rawscore
-* \param is_leafidx
-* \param num_iteration number of iteration for prediction, <= 0 means no limit
-* \param out prediction result
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterPredictForMat_R(
-  LGBM_SE handle,
-  SEXP data,
-  SEXP num_row,
-  SEXP num_col,
-  SEXP is_rawscore,
-  SEXP is_leafidx,
-  SEXP is_predcontrib,
-  SEXP start_iteration,
-  SEXP num_iteration,
-  SEXP parameter,
-  SEXP out_result
-);
-
-/*!
-* \brief save model into file
-* \param handle handle
-* \param num_iteration, <= 0 means save all
-* \param filename file name
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterSaveModel_R(
-  LGBM_SE handle,
-  SEXP num_iteration,
-  SEXP feature_importance_type,
-  SEXP filename
-);
-
-/*!
-* \brief create string containing model
-* \param handle handle
-* \param num_iteration, <= 0 means save all
-* \param out_str string of model
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterSaveModelToString_R(
-  LGBM_SE handle,
-  SEXP num_iteration,
-  SEXP feature_importance_type,
-  SEXP buffer_len,
-  SEXP actual_len,
-  LGBM_SE out_str
-);
-
-/*!
-* \brief dump model to json
-* \param handle handle
-* \param num_iteration, <= 0 means save all
-* \param out_str json format string of model
-* \return 0 when succeed, -1 when failure happens
-*/
-LIGHTGBM_C_EXPORT SEXP LGBM_BoosterDumpModel_R(
-  LGBM_SE handle,
-  SEXP num_iteration,
-  SEXP feature_importance_type,
-  SEXP buffer_len,
-  SEXP actual_len,
-  LGBM_SE out_str
-);
-
-#endif  // LIGHTGBM_R_H_
diff --git a/README.md b/README.md
index f56c67ad1..4793cd73a 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,170 @@
 # FairGBM
 
-_Under construction; will be released in mid September._
+> **Under Construction**; release date: 16th of September.
+
+FairGBM is an easy-to-use and lightweight fairness-aware ML algorithm with state-of-the-art performance on tabular datasets.
+
+FairGBM builds upon the popular [LightGBM](https://github.com/microsoft/LightGBM) algorithm and adds customizable 
+constraints for group-wise fairness (_e.g._, equal opportunity, predictive equality) and other global goals (_e.g._, 
+specific Recall or FPR prediction targets).
+
+Please consult [the paper](#citing-fairgbm) for further details.
+
+
+## Install
+
+FairGBM can be installed from [PyPI](https://pypi.org/project/fairgbm/) <!-- TODO: FairGBM pypi link -->
+
+```pip install fairgbm```
+
+or from GitHub
+
+```
+git clone --recurse-submodules https://github.com/feedzai/fairgbm.git
+pip install fairgbm/python-package
+```
+
+## Getting started
+
+You can get FairGBM up and running in just a few lines of Python code:
+
+```python
+from fairgbm import FairGBMClassifier
+
+# Instantiate
+fairgbm_clf = FairGBMClassifier(
+    constraint_type="FNR",    # constraint on equal group-wise TPR (equal opportunity)
+    n_estimators=200,         # core parameters from vanilla LightGBM
+    random_state=42,          # ...
+)
+
+# Train using features (X), labels (Y), and sensitive attributes (S)
+fairgbm_clf.fit(X, Y, constraint_group=S)
+
+# Predict
+Y_test_pred = fairgbm_clf.predict_proba(X_test)[:, -1]  # Compute continuous class probabilities (recommended)
+# Y_test_pred = fairgbm_clf.predict(X_test)             # Or compute discrete class predictions
+```
+
+A more in-depth explanation and other usage examples can be found in the [**_examples folder_**](/examples).
+
+**For Python examples see the [_notebooks folder_](/examples/FairGBM-python-notebooks).**
+
+
+## Features
+
+FairGBM enables you to train a GBM model to **minimize a loss function** (_e.g._, cross-entropy) **subject to fairness 
+constraints** (_e.g._, equal opportunity).
+
+Namely, you can target equality of performance metrics (FPR, FNR, or both) across instances from different protected groups (see [fairness constraints](#fairness-constraints) section).
+Simultaneously (and optionally), you can add global constraints on specific metrics (see [global constraints](#global-constraints) section).
+
+### Parameter list
+
+The following parameters can be used as key-word arguments for the `FairGBMClassifier` Python class.
+
+| _Name_ | _Description_ | _Default_ |
+|:------:|---------------|:---------:|
+| `groupwise_constraint_type` | The type of fairness (group-wise equality) constraint to use (if any). | `FPR,FNR` |
+| `global_constraint_type` | The type of global equality constraint to use (if any). | _None_ |
+| `multiplier_learning_rate` | The learning rate for the gradient ascent step (w.r.t. Lagrange multipliers). | `0.1` |
+| `constraint_fpr_tolerance` | The slack when fulfilling _group-wise_ FPR constraints. | `0.01` |
+| `constraint_fnr_tolerance` | The slack when fulfilling _group-wise_ FNR constraints. | `0.01` |
+| `global_target_fpr` | Target rate for the _global_ FPR (inequality) constraint. | _None_ |
+| `global_target_fnr` | Target rate for the _global_ FNR (inequality) constraint. | _None_ |
+| `constraint_stepwise_proxy` | Differentiable proxy for the step-wise function in _group-wise_ constraints. | `cross_entropy` |
+| `objective_stepwise_proxy` | Differentiable proxy for the step-wise function in _global_ constraints. | `cross_entropy` |
+| `stepwise_proxy_margin` | Intercept value for the proxy function: value at `f(logodds=0.0)` | `1.0` |
+| `score_threshold` | Score threshold used when assessing _group-wise_ FPR or FNR in training. | `0.5` |
+| `global_score_threshold` | Score threshold used when assessing _global_ FPR or FNR in training. | `0.5` |
+| `init_multipliers` | The initial value of the Lagrange multipliers. | `0` for each constraint |
+| ... | _Any core [`LGBMClassifier` parameter](https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMClassifier.html#lightgbm-lgbmclassifier) can be used with FairGBM as well._ |  |
+
+Please consult [this list](https://lightgbm.readthedocs.io/en/latest/Parameters.html#core-parameters) for a detailed
+view of all vanilla LightGBM parameters (_e.g._, `n_estimators`, `n_jobs`, ...).
+
+> **Note** 
+> The `objective` is the only core LightGBM parameter that cannot be changed when using FairGBM, as you must use
+> the constrained loss function `objective="constrained_cross_entropy"`.
+> Using a standard non-constrained objective will fallback to using standard LightGBM.
+
+
+### Fairness constraints
+
+You can use FairGBM to equalize the following metrics across protected groups:
+- Equalize FNR (equivalent to equalizing TPR or Recall)
+    - also known as _equal opportunity_ [(Hardt _et al._, 2016)](https://arxiv.org/abs/1610.02413)
+- Equalize FPR (equivalent to equalizing TNR or Specificity)
+    - also known as _predictive equality_ [(Corbett-Davies _et al._, 2017)](https://arxiv.org/abs/1701.08230)
+- Equalize both FNR and FPR simultaneously
+    - also known as _equal odds_ [(Hardt _et al._, 2016)](https://arxiv.org/abs/1610.02413)
+
+> **Example for _equality of opportunity_** in college admissions:
+> your likelihood of getting admitted to a certain college (predicted positive) given that you're a qualified candidate
+> (label positive) should be the same regardless of your race (sensitive attribute).
+
+<!--
+Take the following hypothetical example:
+
+If you're training an algorithm to predict mortgage defaults, a valuable fairness criterion may be equalizing FPR 
+among people from different ethnicities.
+This ensures that for two people that will successfully repay their loans, their likelihood of being wrongly denied
+access to credit is the same regardless of ethnicity.
+This is known as a _punitive_ setting, as a positive prediction (predicted to default) leads to a negative outcome
+(loan application denied).
+
+Conversely, if you're training an ML model in an _assistive_ setting (_i.e._, a positive prediction leads to a 
+positive outcome for the person), you may want to target equalizing FNR.
+-->
+
+### Global constraints
+
+You can also target specific TPR or FPR goals.
+For example, in cases where high accuracy is trivially achieved (_e.g._, problems with high class imbalance),
+you may want to maximize TPR with a constraint on FPR (_e.g._, "maximize TPR with at most 5% FPR").
+You can achieve this by setting a constraint on `global FPR ≤ 0.05`.
+
+You can simultaneously set constraints on group-wise metrics (fairness constraints) and constraints on global metrics.
+[This notebook](/examples/FairGBM-python-notebooks) shows an example on a highly class imbalanced dataset that makes use of both group-level and global constraints.
+
+
+## Technical Details
+
+FairGBM is a framework that enables _constrained optimization_ of Gradient Boosting Machines (GBMs).
+This way, we can train a GBM model to minimize some loss function (usually the _binary cross-entropy_) subject to a set
+of constraints that should be met in the training dataset (_e.g._, equality of opportunity).
+
+FairGBM applies the [method of Lagrange multipliers](https://en.wikipedia.org/wiki/Lagrange_multiplier), and uses 
+iterative and interleaved steps of gradient descent (on the function space, by adding new trees to the GBM model) and 
+gradient ascent (on the space of Lagrange multipliers, **Λ**).
+
+The main obstacle with enforcing fairness constraints in training is that these constraints are often 
+_non-differentiable_. To side-step this issue, we use a differentiable proxy of the step-wise function.
+The following plot shows an example of _hinge-based_ and _cross-entropy-based_ proxies for the _false positive_ value
+of a _label negative_ instance.
+
+<p align="center">
+    <img src="https://user-images.githubusercontent.com/13498941/189664020-70ebbae4-6b93-4f38-af7d-f870381a8a22.png" width="40%" alt="example of proxy FPR function" />
+</p>
+
+For a more in-depth explanation of FairGBM please consult [the paper](#citing-fairgbm).
+
+[comment]: <> (### Important C++ source files **TODO**)
+
+
+[comment]: <> (## Results)
+[comment]: <> (%% TODO: results and run-time comparisons against fairlearn, TFCO, and others)
+
+
+## Citing FairGBM
+
+The paper is publicly available at this [arXiv link](https://arxiv.org/abs/2103.12715). _**TODO: update with correct link and reference**_
+
+```
+@article{cruz2022fairgbm,
+  title={FairGBM: Gradient Boosting with Fairness Constraints},
+  author={Cruz, Andr{\'e} F and Bel{\'e}m, Catarina and Bravo, Jo\~{a}o and Saleiro, Pedro and Bizarro, Pedro},
+  journal={},  %%TBD
+  year={2022}
+}
+```
diff --git a/VERSION.txt b/VERSION.txt
index 3ca4a7207..6f060dcbc 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1,1 +1,1 @@
-3.2.1.99
+0.9.9
\ No newline at end of file
diff --git a/build-cran-package.sh b/build-cran-package.sh
deleted file mode 100755
index 318b96fde..000000000
--- a/build-cran-package.sh
+++ /dev/null
@@ -1,147 +0,0 @@
-#!/bin/sh
-
-# [description]
-#     Prepare a source distribution of the R package
-#     to be submitted to CRAN.
-#
-# [usage]
-#     sh build-cran-package.sh
-
-set -e
-
-ORIG_WD=$(pwd)
-TEMP_R_DIR=$(pwd)/lightgbm_r
-
-if test -d ${TEMP_R_DIR}; then
-    rm -r ${TEMP_R_DIR}
-fi
-mkdir -p ${TEMP_R_DIR}
-
-CURRENT_DATE=$(date +'%Y-%m-%d')
-
-# R packages cannot have versions like 3.0.0rc1, but
-# 3.0.0-1 is acceptable
-LGB_VERSION=$(cat VERSION.txt | sed "s/rc/-/g")
-
-# move relevant files
-cp -R R-package/* ${TEMP_R_DIR}
-cp -R include ${TEMP_R_DIR}/src/
-cp -R src/* ${TEMP_R_DIR}/src/
-
-cp \
-    external_libs/fast_double_parser/include/fast_double_parser.h \
-    ${TEMP_R_DIR}/src/include/LightGBM
-
-mkdir -p ${TEMP_R_DIR}/src/include/LightGBM/fmt
-cp \
-    external_libs/fmt/include/fmt/*.h \
-    ${TEMP_R_DIR}/src/include/LightGBM/fmt/
-
-# including only specific files from Eigen, to keep the R package
-# small and avoid redistributing code with licenses incompatible with
-# LightGBM's license
-EIGEN_R_DIR=${TEMP_R_DIR}/src/include/Eigen
-mkdir -p ${EIGEN_R_DIR}
-
-modules="Cholesky Core Dense Eigenvalues Geometry Householder Jacobi LU QR SVD"
-for eigen_module in ${modules}; do
-    cp external_libs/eigen/Eigen/${eigen_module} ${EIGEN_R_DIR}/${eigen_module}
-    if [ ${eigen_module} != "Dense" ]; then
-        mkdir -p ${EIGEN_R_DIR}/src/${eigen_module}/
-        cp -R external_libs/eigen/Eigen/src/${eigen_module}/* ${EIGEN_R_DIR}/src/${eigen_module}/
-    fi
-done
-
-mkdir -p ${EIGEN_R_DIR}/src/misc
-cp -R external_libs/eigen/Eigen/src/misc/* ${EIGEN_R_DIR}/src/misc/
-
-mkdir -p ${EIGEN_R_DIR}/src/plugins
-cp -R external_libs/eigen/Eigen/src/plugins/* ${EIGEN_R_DIR}/src/plugins/
-
-cd ${TEMP_R_DIR}
-
-    # Remove files not needed for CRAN
-    echo "Removing files not needed for CRAN"
-    rm src/install.libs.R
-    rm -r inst/
-    rm -r pkgdown/
-    rm cran-comments.md
-    rm AUTOCONF_UBUNTU_VERSION
-    rm recreate-configure.sh
-
-    # files only used by the lightgbm CLI aren't needed for
-    # the R package
-    rm src/application/application.cpp
-    rm src/include/LightGBM/application.h
-    rm src/main.cpp
-
-    # configure.ac and DESCRIPTION have placeholders for version
-    # and date so they don't have to be updated manually
-    sed -i.bak -e "s/~~VERSION~~/${LGB_VERSION}/" configure.ac
-    sed -i.bak -e "s/~~VERSION~~/${LGB_VERSION}/" DESCRIPTION
-    sed -i.bak -e "s/~~DATE~~/${CURRENT_DATE}/" DESCRIPTION
-
-    # Remove 'region', 'endregion', and 'warning' pragmas.
-    # This won't change the correctness of the code. CRAN does
-    # not allow you to use compiler flag '-Wno-unknown-pragmas' or
-    # pragmas that suppress warnings.
-    echo "Removing unknown pragmas in headers"
-    for file in $(find . -name '*.h' -o -name '*.hpp' -o -name '*.cpp'); do
-      sed \
-        -i.bak \
-        -e 's/^.*#pragma clang diagnostic.*$//' \
-        -e 's/^.*#pragma diag_suppress.*$//' \
-        -e 's/^.*#pragma GCC diagnostic.*$//' \
-        -e 's/^.*#pragma region.*$//' \
-        -e 's/^.*#pragma endregion.*$//' \
-        -e 's/^.*#pragma warning.*$//' \
-        "${file}"
-    done
-    find . -name '*.h.bak' -o -name '*.hpp.bak' -o -name '*.cpp.bak' -exec rm {} \;
-
-    sed \
-        -i.bak \
-        -e 's/\.\..*fmt\/format\.h/LightGBM\/fmt\/format\.h/' \
-        src/include/LightGBM/utils/common.h
-
-    sed \
-        -i.bak \
-        -e 's/\.\..*fast_double_parser\.h/LightGBM\/fast_double_parser\.h/' \
-        src/include/LightGBM/utils/common.h
-
-    # When building an R package with 'configure', it seems
-    # you're guaranteed to get a shared library called
-    #  <packagename>.so/dll. The package source code expects
-    # 'lib_lightgbm.so', not 'lightgbm.so', to comply with the way
-    # this project has historically handled installation
-    echo "Changing lib_lightgbm to lightgbm"
-    for file in R/*.R; do
-        sed \
-            -i.bak \
-            -e 's/lib_lightgbm/lightgbm/' \
-            "${file}"
-    done
-    sed \
-        -i.bak \
-        -e 's/lib_lightgbm/lightgbm/' \
-        NAMESPACE
-
-    # 'processx' is listed as a 'Suggests' dependency in DESCRIPTION
-    # because it is used in install.libs.R, a file that is not
-    # included in the CRAN distribution of the package
-    sed \
-        -i.bak \
-        '/processx/d' \
-        DESCRIPTION
-
-    echo "Cleaning sed backup files"
-    rm R/*.R.bak
-    rm NAMESPACE.bak
-
-cd ${ORIG_WD}
-
-R CMD build \
-    --keep-empty-dirs \
-    lightgbm_r
-
-echo "Done building R package"
diff --git a/build_r.R b/build_r.R
deleted file mode 100644
index f7765eb41..000000000
--- a/build_r.R
+++ /dev/null
@@ -1,436 +0,0 @@
-# For macOS users who have decided to use gcc
-# (replace 8 with version of gcc installed on your machine)
-# NOTE: your gcc / g++ from Homebrew is probably in /usr/local/bin
-#export CXX=/usr/local/bin/g++-8 CC=/usr/local/bin/gcc-8
-# Sys.setenv("CXX" = "/usr/local/bin/g++-8")
-# Sys.setenv("CC" = "/usr/local/bin/gcc-8")
-
-args <- commandArgs(trailingOnly = TRUE)
-INSTALL_AFTER_BUILD <- !("--skip-install" %in% args)
-TEMP_R_DIR <- file.path(getwd(), "lightgbm_r")
-TEMP_SOURCE_DIR <- file.path(TEMP_R_DIR, "src")
-
-# [description]
-#     Parse the content of commandArgs() into a structured
-#     list. This returns a list with two sections.
-#       * "flags" = a character of vector of flags like "--use-gpu"
-#       * "keyword_args" = a named character vector, where names
-#           refer to options and values are the option values. For
-#           example, c("--boost-librarydir" = "/usr/lib/x86_64-linux-gnu")
-.parse_args <- function(args) {
-  out_list <- list(
-    "flags" = character(0L)
-    , "keyword_args" = character(0L)
-  )
-  for (arg in args) {
-    if (any(grepl("=", arg))) {
-      split_arg <- strsplit(arg, "=")[[1L]]
-      arg_name <- split_arg[[1L]]
-      arg_value <- split_arg[[2L]]
-      out_list[["keyword_args"]][[arg_name]] <- arg_value
-    } else {
-      out_list[["flags"]] <- c(out_list[["flags"]], arg)
-    }
-  }
-  return(out_list)
-}
-parsed_args <- .parse_args(args)
-
-USING_GPU <- "--use-gpu" %in% parsed_args[["flags"]]
-USING_MINGW <- "--use-mingw" %in% parsed_args[["flags"]]
-USING_MSYS2 <- "--use-msys2" %in% parsed_args[["flags"]]
-
-# this maps command-line arguments to defines passed into CMake,
-ARGS_TO_DEFINES <- c(
-  "--boost-root" = "-DBOOST_ROOT"
-  , "--boost-dir" = "-DBoost_DIR"
-  , "--boost-include-dir" = "-DBoost_INCLUDE_DIR"
-  , "--boost-librarydir" = "-DBOOST_LIBRARYDIR"
-  , "--opencl-include-dir" = "-DOpenCL_INCLUDE_DIR"
-  , "--opencl-library" = "-DOpenCL_LIBRARY"
-)
-
-recognized_args <- c(
-  "--skip-install"
-  , "--use-gpu"
-  , "--use-mingw"
-  , "--use-msys2"
-  , names(ARGS_TO_DEFINES)
-)
-given_args <- c(
-  parsed_args[["flags"]]
-  , names(parsed_args[["keyword_args"]])
-)
-unrecognized_args <- setdiff(given_args, recognized_args)
-if (length(unrecognized_args) > 0L) {
-  msg <- paste0(
-    "Unrecognized arguments: "
-    , paste0(unrecognized_args, collapse = ", ")
-  )
-  stop(msg)
-}
-
-# [description] Replace statements in install.libs.R code based on
-#               command-line flags
-.replace_flag <- function(variable_name, value, content) {
-  out <- gsub(
-    pattern = paste0(variable_name, " <-.*")
-    , replacement = paste0(variable_name, " <- ", as.character(value))
-    , x = content
-  )
-  return(out)
-}
-
-install_libs_content <- readLines(
-  file.path("R-package", "src", "install.libs.R")
-)
-install_libs_content <- .replace_flag("use_gpu", USING_GPU, install_libs_content)
-install_libs_content <- .replace_flag("use_mingw", USING_MINGW, install_libs_content)
-install_libs_content <- .replace_flag("use_msys2", USING_MSYS2, install_libs_content)
-
-# set up extra flags based on keyword arguments
-keyword_args <- parsed_args[["keyword_args"]]
-if (length(keyword_args) > 0L) {
-  cmake_args_to_add <- NULL
-  for (i in seq_len(length(keyword_args))) {
-    arg_name <- names(keyword_args)[[i]]
-    define_name <- ARGS_TO_DEFINES[[arg_name]]
-    arg_value <- shQuote(keyword_args[[arg_name]])
-    cmake_args_to_add <- c(cmake_args_to_add, paste0(define_name, "=", arg_value))
-  }
-  install_libs_content <- gsub(
-    pattern = paste0("command_line_args <- NULL")
-    , replacement = paste0(
-      "command_line_args <- c(\""
-      , paste(cmake_args_to_add, collapse = "\", \"")
-      , "\")"
-    )
-    , x = install_libs_content
-  )
-}
-
-# R returns FALSE (not a non-zero exit code) if a file copy operation
-# breaks. Let's fix that
-.handle_result <- function(res) {
-  if (!all(res)) {
-    stop("Copying files failed!")
-  }
-  return(invisible(NULL))
-}
-
-# system() will not raise an R exception if the process called
-# fails. Wrapping it here to get that behavior.
-#
-# system() introduces a lot of overhead, at least on Windows,
-# so trying processx if it is available
-.run_shell_command <- function(cmd, args, strict = TRUE) {
-    on_windows <- .Platform$OS.type == "windows"
-    has_processx <- suppressMessages({
-      suppressWarnings({
-        require("processx")  # nolint
-      })
-    })
-    if (has_processx && on_windows) {
-      result <- processx::run(
-        command = cmd
-        , args = args
-        , windows_verbatim_args = TRUE
-        , error_on_status = FALSE
-        , echo = TRUE
-      )
-      exit_code <- result$status
-    } else {
-      if (on_windows) {
-        message(paste0(
-          "Using system() to run shell commands. Installing "
-          , "'processx' with install.packages('processx') might "
-          , "make this faster."
-        ))
-      }
-      cmd <- paste0(cmd, " ", paste0(args, collapse = " "))
-      exit_code <- system(cmd)
-    }
-
-    if (exit_code != 0L && isTRUE(strict)) {
-        stop(paste0("Command failed with exit code: ", exit_code))
-    }
-    return(invisible(exit_code))
-}
-
-# Make a new temporary folder to work in
-unlink(x = TEMP_R_DIR, recursive = TRUE)
-dir.create(TEMP_R_DIR)
-
-# copy in the relevant files
-result <- file.copy(
-  from = "R-package/./"
-  , to = sprintf("%s/", TEMP_R_DIR)
-  , recursive = TRUE
-  , overwrite = TRUE
-)
-.handle_result(result)
-
-# overwrite src/install.libs.R with new content based on command-line flags
-writeLines(
-  text = install_libs_content
-  , con = file.path(TEMP_SOURCE_DIR, "install.libs.R")
-)
-
-# Add blank Makevars files
-result <- file.copy(
-  from = file.path(TEMP_R_DIR, "inst", "Makevars")
-  , to = file.path(TEMP_SOURCE_DIR, "Makevars")
-  , overwrite = TRUE
-)
-.handle_result(result)
-result <- file.copy(
-  from = file.path(TEMP_R_DIR, "inst", "Makevars.win")
-  , to = file.path(TEMP_SOURCE_DIR, "Makevars.win")
-  , overwrite = TRUE
-)
-.handle_result(result)
-
-result <- file.copy(
-  from = "include/"
-  , to =  sprintf("%s/", TEMP_SOURCE_DIR)
-  , recursive = TRUE
-  , overwrite = TRUE
-)
-.handle_result(result)
-
-result <- file.copy(
-  from = "src/"
-  , to = sprintf("%s/", TEMP_SOURCE_DIR)
-  , recursive = TRUE
-  , overwrite = TRUE
-)
-.handle_result(result)
-
-EIGEN_R_DIR <- file.path(TEMP_SOURCE_DIR, "include", "Eigen")
-dir.create(EIGEN_R_DIR)
-
-eigen_modules <- c(
-  "Cholesky"
-  , "Core"
-  , "Dense"
-  , "Eigenvalues"
-  , "Geometry"
-  , "Householder"
-  , "Jacobi"
-  , "LU"
-  , "QR"
-  , "SVD"
-)
-for (eigen_module in eigen_modules) {
-  result <- file.copy(
-    from = file.path("external_libs", "eigen", "Eigen", eigen_module)
-    , to = EIGEN_R_DIR
-    , recursive = FALSE
-    , overwrite = TRUE
-  )
-  .handle_result(result)
-}
-
-dir.create(file.path(EIGEN_R_DIR, "src"))
-
-for (eigen_module in c(eigen_modules, "misc", "plugins")) {
-  if (eigen_module == "Dense") {
-    next
-  }
-  module_dir <- file.path(EIGEN_R_DIR, "src", eigen_module)
-  dir.create(module_dir, recursive = TRUE)
-  result <- file.copy(
-    from = sprintf("%s/", file.path("external_libs", "eigen", "Eigen", "src", eigen_module))
-    , to = sprintf("%s/", file.path(EIGEN_R_DIR, "src"))
-    , recursive = TRUE
-    , overwrite = TRUE
-  )
-  .handle_result(result)
-}
-
-.replace_pragmas <- function(filepath) {
-  pragma_patterns <- c(
-    "^.*#pragma clang diagnostic.*$"
-    , "^.*#pragma diag_suppress.*$"
-    , "^.*#pragma GCC diagnostic.*$"
-    , "^.*#pragma region.*$"
-    , "^.*#pragma endregion.*$"
-    , "^.*#pragma warning.*$"
-  )
-  content <- readLines(filepath)
-  for (pragma_pattern in pragma_patterns) {
-    content <- content[!grepl(pragma_pattern, content)]
-  }
-  writeLines(content, filepath)
-}
-
-# remove pragmas that suppress warnings, to appease R CMD check
-.replace_pragmas(
-  file.path(EIGEN_R_DIR, "src", "Core", "arch", "SSE", "Complex.h")
-)
-.replace_pragmas(
-  file.path(EIGEN_R_DIR, "src", "Core", "util", "DisableStupidWarnings.h")
-)
-
-result <- file.copy(
-  from = "CMakeLists.txt"
-  , to = file.path(TEMP_R_DIR, "inst", "bin/")
-  , overwrite = TRUE
-)
-.handle_result(result)
-
-# remove CRAN-specific files
-result <- file.remove(
-  file.path(TEMP_R_DIR, "cleanup")
-  , file.path(TEMP_R_DIR, "configure")
-  , file.path(TEMP_R_DIR, "configure.ac")
-  , file.path(TEMP_R_DIR, "configure.win")
-  , file.path(TEMP_SOURCE_DIR, "Makevars.in")
-  , file.path(TEMP_SOURCE_DIR, "Makevars.win.in")
-)
-.handle_result(result)
-
-#------------#
-# submodules #
-#------------#
-EXTERNAL_LIBS_R_DIR <- file.path(TEMP_SOURCE_DIR, "external_libs")
-dir.create(EXTERNAL_LIBS_R_DIR)
-for (submodule in list.dirs(
-  path = "external_libs"
-  , full.names = FALSE
-  , recursive = FALSE
-)) {
-  # compute/ is a submodule with boost, only needed if
-  # building the R package with GPU support;
-  # eigen/ has a special treatment due to licensing aspects
-  if ((submodule == "compute" && !USING_GPU) || submodule == "eigen") {
-    next
-  }
-  result <- file.copy(
-    from = sprintf("%s/", file.path("external_libs", submodule))
-    , to = sprintf("%s/", EXTERNAL_LIBS_R_DIR)
-    , recursive = TRUE
-    , overwrite = TRUE
-  )
-  .handle_result(result)
-}
-
-# copy files into the place CMake expects
-CMAKE_MODULES_R_DIR <- file.path(TEMP_SOURCE_DIR, "cmake", "modules")
-dir.create(CMAKE_MODULES_R_DIR, recursive = TRUE)
-result <- file.copy(
-  from = file.path("cmake", "modules", "FindLibR.cmake")
-  , to = sprintf("%s/", CMAKE_MODULES_R_DIR)
-  , overwrite = TRUE
-)
-.handle_result(result)
-for (src_file in c("lightgbm_R.cpp", "lightgbm_R.h", "R_object_helper.h")) {
-  result <- file.copy(
-    from = file.path(TEMP_SOURCE_DIR, src_file)
-    , to = file.path(TEMP_SOURCE_DIR, "src", src_file)
-    , overwrite = TRUE
-  )
-  .handle_result(result)
-  result <- file.remove(
-    file.path(TEMP_SOURCE_DIR, src_file)
-  )
-  .handle_result(result)
-}
-
-result <- file.copy(
-  from = file.path("R-package", "inst", "make-r-def.R")
-  , to = file.path(TEMP_R_DIR, "inst", "bin/")
-  , overwrite = TRUE
-)
-.handle_result(result)
-
-# R packages cannot have versions like 3.0.0rc1, but
-# 3.0.0-1 is acceptable
-LGB_VERSION <- readLines("VERSION.txt")[1L]
-LGB_VERSION <- gsub(
-  pattern = "rc"
-  , replacement = "-"
-  , x = LGB_VERSION
-)
-
-# DESCRIPTION has placeholders for version
-# and date so it doesn't have to be updated manually
-DESCRIPTION_FILE <- file.path(TEMP_R_DIR, "DESCRIPTION")
-description_contents <- readLines(DESCRIPTION_FILE)
-description_contents <- gsub(
-  pattern = "~~VERSION~~"
-  , replacement = LGB_VERSION
-  , x = description_contents
-)
-description_contents <- gsub(
-  pattern = "~~DATE~~"
-  , replacement = as.character(Sys.Date())
-  , x = description_contents
-)
-writeLines(description_contents, DESCRIPTION_FILE)
-
-# CMake-based builds can't currently use R's builtin routine registration,
-# so have to update NAMESPACE manually, with a statement like this:
-#
-# useDynLib(lib_lightgbm, LGBM_GetLastError_R, LGBM_DatasetCreateFromFile_R, ...)
-#
-# See https://cran.r-project.org/doc/manuals/r-release/R-exts.html#useDynLib for
-# documentation of this approach, where the NAMESPACE file uses a statement like
-# useDynLib(foo, myRoutine, myOtherRoutine)
-NAMESPACE_FILE <- file.path(TEMP_R_DIR, "NAMESPACE")
-namespace_contents <- readLines(NAMESPACE_FILE)
-dynlib_line <- grep(
-  pattern = "^useDynLib"
-  , x = namespace_contents
-)
-
-c_api_contents <- readLines(file.path(TEMP_SOURCE_DIR, "src", "lightgbm_R.h"))
-c_api_contents <- c_api_contents[grepl("^LIGHTGBM_C_EXPORT", c_api_contents)]
-c_api_contents <- gsub(
-  pattern = "LIGHTGBM_C_EXPORT LGBM_SE "
-  , replacement = ""
-  , x = c_api_contents
-)
-c_api_contents <- gsub(
-  pattern = "LIGHTGBM_C_EXPORT SEXP "
-  , replacement = ""
-  , x = c_api_contents
-)
-c_api_symbols <- gsub(
-  pattern = "\\(.*"
-  , replacement = ""
-  , x = c_api_contents
-)
-dynlib_statement <- paste0(
-  "useDynLib(lib_lightgbm, "
-  , paste0(c_api_symbols, collapse = ", ")
-  , ")"
-)
-namespace_contents[dynlib_line] <- dynlib_statement
-writeLines(namespace_contents, NAMESPACE_FILE)
-
-# NOTE: --keep-empty-dirs is necessary to keep the deep paths expected
-#       by CMake while also meeting the CRAN req to create object files
-#       on demand
-.run_shell_command("R", c("CMD", "build", TEMP_R_DIR, "--keep-empty-dirs"))
-
-# Install the package
-version <- gsub(
-  "Version: ",
-  "",
-  grep(
-    "Version: "
-    , readLines(con = file.path(TEMP_R_DIR, "DESCRIPTION"))
-    , value = TRUE
-  )
-)
-tarball <- file.path(getwd(), sprintf("lightgbm_%s.tar.gz", version))
-
-install_cmd <- "R"
-install_args <- c("CMD", "INSTALL", "--no-multiarch", "--with-keep.source", tarball)
-if (INSTALL_AFTER_BUILD) {
-  .run_shell_command(install_cmd, install_args)
-} else {
-  cmd <- paste0(install_cmd, " ", paste0(install_args, collapse = " "))
-  print(sprintf("Skipping installation. Install the package with command '%s'", cmd))
-}
diff --git a/docker/README.md b/docker/README.md
deleted file mode 100644
index ab9bd75ef..000000000
--- a/docker/README.md
+++ /dev/null
@@ -1,124 +0,0 @@
-﻿# Using LightGBM via Docker
-
-This directory contains `Dockerfile`s to make it easy to build and run LightGBM via [Docker](https://www.docker.com/).
-
-## Installing Docker
-
-Follow the general installation instructions [on the Docker site](https://docs.docker.com/install/):
-
-* [macOS](https://docs.docker.com/docker-for-mac/install/)
-* [Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/)
-* [Windows](https://docs.docker.com/docker-for-windows/install/)
-
-## Using CLI Version of LightGBM via Docker
-
-Build a Docker image with LightGBM CLI:
-
-```
-mkdir lightgbm-docker
-cd lightgbm-docker
-wget https://raw.githubusercontent.com/Microsoft/LightGBM/master/docker/dockerfile-cli
-docker build -t lightgbm-cli -f dockerfile-cli .
-```
-
-where `lightgbm-cli` is the desired Docker image name.
-
-Run the CLI from the container:
-
-```
-docker run --rm -it \
---volume $HOME/lgbm.conf:/lgbm.conf \
---volume $HOME/model.txt:/model.txt \
---volume $HOME/tmp:/out \
-lightgbm-cli \
-config=lgbm.conf
-```
-
-In the above example, three volumes are [mounted](https://docs.docker.com/engine/reference/commandline/run/#mount-volume--v---read-only)
-from the host machine to the Docker container:
-
-* `lgbm.conf` - task config, for example
-
-```
-app=multiclass
-num_class=3
-task=convert_model
-input_model=model.txt
-convert_model=/out/predict.cpp
-convert_model_language=cpp
-```
-
-* `model.txt` - an input file for the task, could be training data or, in this case, a pre-trained model.
-* `out` - a directory to store the output of the task, notice that `convert_model` in the task config is using it.
-
-`config=lgbm.conf` is a command-line argument passed to the `lightgbm` executable, more arguments can be passed if required.
-
-## Running the Python-package Сontainer
-
-Build the container, for Python users:
-
-```
-mkdir lightgbm-docker
-cd lightgbm-docker
-wget https://raw.githubusercontent.com/Microsoft/LightGBM/master/docker/dockerfile-python
-docker build -t lightgbm -f dockerfile-python .
-```
-
-After build finished, run the container:
-
-```
-docker run --rm -it lightgbm
-```
-
-## Running the R-package Сontainer
-
-Build the container based on the [`verse` Rocker image](https://www.rocker-project.org/images/), for R users:
-
-```
-mkdir lightgbm-docker
-cd lightgbm-docker
-wget https://raw.githubusercontent.com/Microsoft/LightGBM/master/docker/dockerfile-r
-docker build -t lightgbm-r -f dockerfile-r .
-```
-
-This will default to the latest version of R. If you want to try with an older `rocker` container to run a particular version of R, pass in a build arg with [a valid tag](https://hub.docker.com/r/rocker/verse/tags).
-
-For example, to test with R 3.5:
-
-```
-docker build \
-    -t lightgbm-r-35 \
-    -f dockerfile-r \
-    --build-arg R_VERSION=3.5 \
-    .
-```
-
-After the build is finished you have two options to run the container:
-
-1. Start [RStudio](https://www.rstudio.com/products/rstudio/), an interactive development environment, so that you can develop your analysis using LightGBM or simply try out the R package. You can open RStudio in your web browser.
-2. Start a regular R session.
-
-In both cases you can simply call
-
-```
-library("lightgbm")
-```
-
-to load the installed LightGBM R package.
-
-**RStudio**
-
-```
-docker run --rm -it -e PASSWORD=lightgbm -p 8787:8787 lightgbm-r
-```
-
-Open the browser at http://localhost:8787 and log in.
-See the [`rocker/rstudio`](https://hub.docker.com/r/rocker/rstudio) image documentation for further configuration options.
-
-**Regular R**
-
-If you just want a vanilla R process, change the executable of the container:
-
-```
-docker run --rm -it lightgbm-r R
-```
diff --git a/docker/dockerfile-cli b/docker/dockerfile-cli
deleted file mode 100644
index e033f1c51..000000000
--- a/docker/dockerfile-cli
+++ /dev/null
@@ -1,22 +0,0 @@
-FROM ubuntu:16.04
-
-RUN apt-get update && \
-    apt-get install -y --no-install-recommends \
-        ca-certificates \
-        cmake \
-        build-essential \
-        gcc \
-        g++ \
-        git && \
-    rm -rf /var/lib/apt/lists/*
-
-RUN git clone --recursive --branch stable --depth 1 https://github.com/Microsoft/LightGBM && \
-    mkdir LightGBM/build && \
-    cd LightGBM/build && \
-    cmake .. && \
-    make -j4 && \
-    make install && \
-    cd ../.. && \
-    rm -rf LightGBM
-
-ENTRYPOINT ["lightgbm"]
diff --git a/docker/dockerfile-python b/docker/dockerfile-python
deleted file mode 100644
index ae37c9332..000000000
--- a/docker/dockerfile-python
+++ /dev/null
@@ -1,27 +0,0 @@
-FROM ubuntu:16.04
-
-ARG CONDA_DIR=/opt/conda
-ENV PATH $CONDA_DIR/bin:$PATH
-
-RUN apt-get update && \
-    apt-get install -y --no-install-recommends \
-        ca-certificates \
-        cmake \
-        build-essential \
-        gcc \
-        g++ \
-        curl \
-        git && \
-    # python environment
-    curl -sL https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -o conda.sh && \
-    /bin/bash conda.sh -f -b -p $CONDA_DIR && \
-    export PATH="$CONDA_DIR/bin:$PATH" && \
-    conda config --set always_yes yes --set changeps1 no && \
-    # lightgbm
-    conda install -q -y numpy scipy scikit-learn pandas && \
-    git clone --recursive --branch stable --depth 1 https://github.com/Microsoft/LightGBM && \
-    cd LightGBM/python-package && python setup.py install && \
-    # clean
-    apt-get autoremove -y && apt-get clean && \
-    conda clean -a -y && \
-    rm -rf /usr/local/src/*
diff --git a/docker/dockerfile-r b/docker/dockerfile-r
deleted file mode 100644
index 1f173cdcd..000000000
--- a/docker/dockerfile-r
+++ /dev/null
@@ -1,12 +0,0 @@
-ARG R_VERSION=latest
-FROM rocker/verse:${R_VERSION}
-
-WORKDIR /lgbm
-
-RUN apt-get update && \
-    apt-get install -y --no-install-recommends \
-        build-essential \
-        cmake && \
-    git clone --recursive --branch stable --depth 1 https://github.com/Microsoft/LightGBM && \
-    cd LightGBM && \
-    Rscript build_r.R
diff --git a/docker/gpu/README.md b/docker/gpu/README.md
deleted file mode 100644
index 13ff2bc68..000000000
--- a/docker/gpu/README.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# Tiny Distroless Dockerfile for LightGBM GPU CLI-only Version
-
-`dockerfile-cli-only-distroless.gpu` - A multi-stage build based on the `nvidia/opencl:devel-ubuntu18.04` (build) and `distroless/cc-debian10` (production) images. LightGBM (CLI-only) can be utilized in GPU and CPU modes. The resulting image size is around 15 MB.
-
----
-
-# Small Dockerfile for LightGBM GPU CLI-only Version
-
-`dockerfile-cli-only.gpu` - A multi-stage build based on the `nvidia/opencl:devel` (build) and `nvidia/opencl:runtime` (production) images. LightGBM (CLI-only) can be utilized in GPU and CPU modes. The resulting image size is around 100 MB.
-
----
-
-# Dockerfile for LightGBM GPU Version with Python
-
-`dockerfile.gpu` - A docker file with LightGBM utilizing nvidia-docker. The file is based on the `nvidia/cuda:8.0-cudnn5-devel` image.
-LightGBM can be utilized in GPU and CPU modes and via Python.
-
-## Contents
-
-- LightGBM (cpu + gpu)
-- Python 3.8 (conda) + scikit-learn, notebooks, pandas, matplotlib
-
-Running the container starts a Jupyter Notebook at `localhost:8888`.
-
-Jupyter password: `keras`.
-
-## Requirements
-
-Requires docker and [nvidia-docker](https://github.com/NVIDIA/nvidia-docker) on host machine.
-
-## Quickstart
-
-### Build Docker Image
-
-```sh
-mkdir lightgbm-docker
-cd lightgbm-docker
-wget https://raw.githubusercontent.com/Microsoft/LightGBM/master/docker/gpu/dockerfile.gpu
-docker build -f dockerfile.gpu -t lightgbm-gpu .
-```
-
-### Run Image
-
-```sh
-nvidia-docker run --rm -d --name lightgbm-gpu -p 8888:8888 -v /home:/home lightgbm-gpu
-```
-
-### Attach with Command Line Access (if required)
-
-```sh
-docker exec -it lightgbm-gpu bash
-```
-
-### Jupyter Notebook
-
-```sh
-localhost:8888
-```
diff --git a/docker/gpu/dockerfile-cli-only-distroless.gpu b/docker/gpu/dockerfile-cli-only-distroless.gpu
deleted file mode 100644
index d391df281..000000000
--- a/docker/gpu/dockerfile-cli-only-distroless.gpu
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright (c) 2020 The Rector and Visitors of the University of Virginia
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the Software without restriction, including without
-# limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is furnished to do so, subject to the following
-# conditions:
-#
-# The above copyright notice and this permission notice shall be included in all copies or substantial portions
-# of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
-# TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
-# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-
-FROM nvidia/opencl:devel-ubuntu18.04 AS build
-ARG DEBIAN_FRONTEND=noninteractive
-ARG OPENCL_LIBRARIES=/usr/lib/x86_64-linux-gnu
-ARG OPENCL_INCLUDE_DIR=/usr/include/CL
-
-# SYSTEM
-RUN apt-get update && apt-get install -y --no-install-recommends \
-        build-essential \
-        git \
-        ca-certificates \
-        libglib2.0-0 \
-        libxext6 \
-        libsm6 \
-        libxrender1 \
-        cmake \
-        libboost-dev \
-        libboost-system-dev \
-        libboost-filesystem-dev \
-        gcc \
-        g++ && \
-    rm -rf /var/lib/apt/lists/*
-
-# LightGBM
-WORKDIR /opt
-RUN git clone --recursive --branch stable --depth 1 https://github.com/Microsoft/LightGBM && \
-    cd LightGBM && mkdir build && cd build && \
-    cmake -DUSE_GPU=1 -DOpenCL_LIBRARY=${OPENCL_LIBRARIES}/libOpenCL.so.1 -DOpenCL_INCLUDE_DIR=$OPENCL_INCLUDE_DIR .. && \
-    make OPENCL_HEADERS=$OPENCL_INCLUDE_DIR LIBOPENCL=$OPENCL_LIBRARIES
-
-FROM gcr.io/distroless/cc-debian10
-COPY --from=build \
-    /opt/LightGBM/lightgbm \
-    /opt/LightGBM/lib_lightgbm.so \
-    /opt/LightGBM/
-COPY --from=build \
-    /usr/lib/x86_64-linux-gnu/libOpenCL.so.1 \
-    /usr/lib/x86_64-linux-gnu/libboost_filesystem.so.1.65.1 \
-    /usr/lib/x86_64-linux-gnu/libboost_system.so.1.65.1 \
-    /usr/lib/x86_64-linux-gnu/libgomp.so.1 \
-    /usr/lib/x86_64-linux-gnu/libstdc++.so.6 \
-    /usr/lib/x86_64-linux-gnu/
-COPY --from=build \
-    /lib/x86_64-linux-gnu/libm.so.6 \
-    /lib/x86_64-linux-gnu/libgcc_s.so.1 \
-    /lib/x86_64-linux-gnu/libpthread.so.0 \
-    /lib/x86_64-linux-gnu/libc.so.6 \
-    /lib/x86_64-linux-gnu/libdl.so.2 \
-    /lib/x86_64-linux-gnu/
-COPY --from=build \
-    /lib64/ld-linux-x86-64.so.2 \
-    /lib64/
-COPY --from=build /etc/OpenCL/vendors/nvidia.icd /etc/OpenCL/vendors/nvidia.icd
-
-ENV PATH /opt/LightGBM:${PATH}
-ENV LANG C.UTF-8
-ENV LC_ALL C.UTF-8
-
-ENTRYPOINT ["lightgbm"]
diff --git a/docker/gpu/dockerfile-cli-only.gpu b/docker/gpu/dockerfile-cli-only.gpu
deleted file mode 100644
index f59cc4548..000000000
--- a/docker/gpu/dockerfile-cli-only.gpu
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright (c) 2020 The Rector and Visitors of the University of Virginia
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
-# documentation files (the "Software"), to deal in the Software without restriction, including without
-# limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
-# Software, and to permit persons to whom the Software is furnished to do so, subject to the following
-# conditions:
-#
-# The above copyright notice and this permission notice shall be included in all copies or substantial portions
-# of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
-# TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
-# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
-
-FROM nvidia/opencl:devel AS build
-ARG DEBIAN_FRONTEND=noninteractive
-ARG OPENCL_LIBRARIES=/usr/lib/x86_64-linux-gnu
-ARG OPENCL_INCLUDE_DIR=/usr/include/CL
-
-# SYSTEM
-RUN apt-get update && apt-get install -y --no-install-recommends \
-        build-essential \
-        git \
-        ca-certificates \
-        libglib2.0-0 \
-        libxext6 \
-        libsm6 \
-        libxrender1 \
-        cmake \
-        libboost-dev \
-        libboost-system-dev \
-        libboost-filesystem-dev \
-        gcc \
-        g++ && \
-    rm -rf /var/lib/apt/lists/*
-
-# LightGBM
-WORKDIR /opt
-RUN git clone --recursive --branch stable --depth 1 https://github.com/Microsoft/LightGBM && \
-    cd LightGBM && mkdir build && cd build && \
-    cmake -DUSE_GPU=1 -DOpenCL_LIBRARY=${OPENCL_LIBRARIES}/libOpenCL.so.1 -DOpenCL_INCLUDE_DIR=$OPENCL_INCLUDE_DIR .. && \
-    make OPENCL_HEADERS=$OPENCL_INCLUDE_DIR LIBOPENCL=$OPENCL_LIBRARIES
-
-FROM nvidia/opencl:runtime
-RUN apt-get update && apt-get install -y --no-install-recommends \
-        libxext6 \
-        libsm6 \
-        libxrender1 \
-        libboost-system-dev \
-        libboost-filesystem-dev \
-        gcc \
-        g++ && \
-    rm -rf /var/lib/apt/lists/*
-
-COPY --from=build \
-    /opt/LightGBM/lightgbm \
-    /opt/LightGBM/lib_lightgbm.so \
-    /opt/LightGBM/
-
-ENV PATH /opt/LightGBM:${PATH}
-ENV LANG C.UTF-8
-ENV LC_ALL C.UTF-8
-
-ENTRYPOINT ["lightgbm"]
diff --git a/docker/gpu/dockerfile.gpu b/docker/gpu/dockerfile.gpu
deleted file mode 100644
index cc1aa43a0..000000000
--- a/docker/gpu/dockerfile.gpu
+++ /dev/null
@@ -1,122 +0,0 @@
-FROM nvidia/cuda:8.0-cudnn5-devel
-
-#################################################################################################################
-#           Global
-#################################################################################################################
-# apt-get to skip any interactive post-install configuration steps with DEBIAN_FRONTEND=noninteractive and apt-get install -y
-
-ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
-ARG DEBIAN_FRONTEND=noninteractive
-
-#################################################################################################################
-#           Global Path Setting
-#################################################################################################################
-
-ENV CUDA_HOME /usr/local/cuda
-ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:${CUDA_HOME}/lib64
-ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH}:/usr/local/lib
-
-ENV OPENCL_LIBRARIES /usr/local/cuda/lib64
-ENV OPENCL_INCLUDE_DIR /usr/local/cuda/include
-
-#################################################################################################################
-#           TINI
-#################################################################################################################
-
-# Install tini
-ENV TINI_VERSION v0.14.0
-ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
-RUN chmod +x /tini
-
-#################################################################################################################
-#           SYSTEM
-#################################################################################################################
-# update: downloads the package lists from the repositories and "updates" them to get information on the newest versions of packages and their
-# dependencies. It will do this for all repositories and PPAs.
-
-RUN apt-get update && \
-apt-get install -y --no-install-recommends \
-build-essential \
-curl \
-bzip2 \
-ca-certificates \
-libglib2.0-0 \
-libxext6 \
-libsm6 \
-libxrender1 \
-git \
-vim \
-mercurial \
-subversion \
-cmake \
-libboost-dev \
-libboost-system-dev \
-libboost-filesystem-dev \
-gcc \
-g++
-
-# Add OpenCL ICD files for LightGBM
-RUN mkdir -p /etc/OpenCL/vendors && \
-    echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd
-
-#################################################################################################################
-#           CONDA
-#################################################################################################################
-
-ARG CONDA_DIR=/opt/conda
-# add to path
-ENV PATH $CONDA_DIR/bin:$PATH
-
-# Install miniconda
-RUN echo "export PATH=$CONDA_DIR/bin:"'$PATH' > /etc/profile.d/conda.sh && \
-    curl -sL https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -o ~/miniconda.sh && \
-    /bin/bash ~/miniconda.sh -b -p $CONDA_DIR && \
-    rm ~/miniconda.sh
-
-RUN conda config --set always_yes yes --set changeps1 no && \
-    conda create -y -q -n py3 python=3.8 mkl numpy scipy scikit-learn jupyter notebook ipython pandas matplotlib
-
-#################################################################################################################
-#           LightGBM
-#################################################################################################################
-
-RUN cd /usr/local/src && mkdir lightgbm && cd lightgbm && \
-    git clone --recursive --branch stable --depth 1 https://github.com/microsoft/LightGBM && \
-    cd LightGBM && mkdir build && cd build && \
-    cmake -DUSE_GPU=1 -DOpenCL_LIBRARY=/usr/local/cuda/lib64/libOpenCL.so -DOpenCL_INCLUDE_DIR=/usr/local/cuda/include/ .. && \
-    make OPENCL_HEADERS=/usr/local/cuda-8.0/targets/x86_64-linux/include LIBOPENCL=/usr/local/cuda-8.0/targets/x86_64-linux/lib
-
-ENV PATH /usr/local/src/lightgbm/LightGBM:${PATH}
-
-RUN /bin/bash -c "source activate py3 && cd /usr/local/src/lightgbm/LightGBM/python-package && python setup.py install --precompile && source deactivate"
-
-#################################################################################################################
-#           System CleanUp
-#################################################################################################################
-# apt-get autoremove: used to remove packages that were automatically installed to satisfy dependencies for some package and that are no more needed.
-# apt-get clean: removes the aptitude cache in /var/cache/apt/archives. You'd be amazed how much is in there! the only drawback is that the packages
-# have to be downloaded again if you reinstall them.
-
-RUN apt-get autoremove -y && apt-get clean && \
-    rm -rf /var/lib/apt/lists/* && \
-    conda clean -a -y
-
-#################################################################################################################
-#           JUPYTER
-#################################################################################################################
-
-# password: keras
-# password key: --NotebookApp.password='sha1:98b767162d34:8da1bc3c75a0f29145769edc977375a373407824'
-
-# Add a notebook profile.
-RUN mkdir -p -m 700 ~/.jupyter/ && \
-    echo "c.NotebookApp.ip = '*'" >> ~/.jupyter/jupyter_notebook_config.py
-
-VOLUME /home
-WORKDIR /home
-
-# IPython
-EXPOSE 8888
-
-ENTRYPOINT [ "/tini", "--" ]
-CMD /bin/bash -c "source activate py3 && jupyter notebook --allow-root --no-browser --NotebookApp.password='sha1:98b767162d34:8da1bc3c75a0f29145769edc977375a373407824' && source deactivate"
diff --git a/examples/FairGBM-python-notebooks/.gitignore b/examples/FairGBM-python-notebooks/.gitignore
new file mode 100644
index 000000000..8fce60300
--- /dev/null
+++ b/examples/FairGBM-python-notebooks/.gitignore
@@ -0,0 +1,1 @@
+data/
diff --git a/examples/FairGBM-python-notebooks/README.md b/examples/FairGBM-python-notebooks/README.md
new file mode 100644
index 000000000..61ff819f2
--- /dev/null
+++ b/examples/FairGBM-python-notebooks/README.md
@@ -0,0 +1,15 @@
+# FairGBM Python Examples
+
+In this folder you can find several FairGBM usage examples.
+
+| _File name_             | _Dataset (size)_ | _Description_ | _Fairness criterion_ |
+|-------------------------|------------------|---------------|----------------------|
+| [UCI-Adult-example.ipynb](UCI-Adult-example.ipynb) | [UCI Adult](https://archive.ics.uci.edu/ml/datasets/adult) (49K) | Simple example on the popular UCI Adult dataset. | Equal TPR (_equal opportunity_) |
+| ... |  | _More examples to come soon_ |  |
+
+<!--
+| [credit-card-fraud-example.ipynb](credit-card-fraud-example.ipynb) | [Credit Card Fraud](https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud) (285K) | Highly class imbalanced dataset in which a trivial classifier achieves 99.8% accuracy. Show-cases the use of both fairness and global constraints! | Equal FPR (predictive equality) |
+| [ACSIncome-example.ipynb](ACSIncome-example.ipynb) | [ACSIncome](https://github.com/zykls/folktables) (1.7M) | Large dataset for comparing run-times of popular fairness-aware algorithms. _Requires a sizeable amount of RAM memory (+32GB)._ | Equal FNR (equal opportunity) |
+-->
+
+Running `pip install -r requirements.txt` installs all requirements for all examples.
diff --git a/examples/FairGBM-python-notebooks/UCI-Adult-example.ipynb b/examples/FairGBM-python-notebooks/UCI-Adult-example.ipynb
new file mode 100644
index 000000000..a566a57f9
--- /dev/null
+++ b/examples/FairGBM-python-notebooks/UCI-Adult-example.ipynb
@@ -0,0 +1,228 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "cff42768",
+   "metadata": {},
+   "source": [
+    "# Simple FairGBM example on the UCI Adult dataset"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "id": "4bdcc068",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from pathlib import Path\n",
+    "import pandas as pd\n",
+    "import numpy as np"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "id": "cbe2ed76",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "SEED = 42"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "10ff123f",
+   "metadata": {},
+   "source": [
+    "### Load data"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "id": "27034067",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "100% [................................................................................] 5229 / 5229"
+     ]
+    }
+   ],
+   "source": [
+    "from utils import load_uci_adult, split_X_Y_S_uci_adult\n",
+    "\n",
+    "train_set, test_set = load_uci_adult()\n",
+    "X_train, Y_train, S_train = split_X_Y_S_uci_adult(train_set)\n",
+    "X_test, Y_test, S_test = split_X_Y_S_uci_adult(test_set);"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "0cad6eeb",
+   "metadata": {},
+   "source": [
+    "###  Construct FairGBM model"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "id": "37bd2985",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from fairgbm import FairGBMClassifier\n",
+    "\n",
+    "core_lgbm_params = {\n",
+    "    \"n_estimators\": 200,\n",
+    "    \"random_state\": SEED,\n",
+    "    \"n_jobs\": -2,\n",
+    "}\n",
+    "\n",
+    "# Instantiate\n",
+    "fairgbm_clf = FairGBMClassifier(\n",
+    "    constraint_type=\"FNR\",    # constraint on equal group-wise TPR (equal opportunity)\n",
+    "    multiplier_learning_rate=0.2,\n",
+    "    constraint_fnr_slack=0.05,\n",
+    "    **core_lgbm_params,\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "4e40397f",
+   "metadata": {},
+   "source": [
+    "### Train model"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "id": "8d64666a",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "CPU times: user 4.12 s, sys: 41.6 ms, total: 4.16 s\n",
+      "Wall time: 545 ms\n"
+     ]
+    },
+    {
+     "data": {
+      "text/html": [
+       "<style>#sk-container-id-1 {color: black;background-color: white;}#sk-container-id-1 pre{padding: 0;}#sk-container-id-1 div.sk-toggleable {background-color: white;}#sk-container-id-1 label.sk-toggleable__label {cursor: pointer;display: block;width: 100%;margin-bottom: 0;padding: 0.3em;box-sizing: border-box;text-align: center;}#sk-container-id-1 label.sk-toggleable__label-arrow:before {content: \"▸\";float: left;margin-right: 0.25em;color: #696969;}#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {color: black;}#sk-container-id-1 div.sk-estimator:hover label.sk-toggleable__label-arrow:before {color: black;}#sk-container-id-1 div.sk-toggleable__content {max-height: 0;max-width: 0;overflow: hidden;text-align: left;background-color: #f0f8ff;}#sk-container-id-1 div.sk-toggleable__content pre {margin: 0.2em;color: black;border-radius: 0.25em;background-color: #f0f8ff;}#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {max-height: 200px;max-width: 100%;overflow: auto;}#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {content: \"▾\";}#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 input.sk-hidden--visually {border: 0;clip: rect(1px 1px 1px 1px);clip: rect(1px, 1px, 1px, 1px);height: 1px;margin: -1px;overflow: hidden;padding: 0;position: absolute;width: 1px;}#sk-container-id-1 div.sk-estimator {font-family: monospace;background-color: #f0f8ff;border: 1px dotted black;border-radius: 0.25em;box-sizing: border-box;margin-bottom: 0.5em;}#sk-container-id-1 div.sk-estimator:hover {background-color: #d4ebff;}#sk-container-id-1 div.sk-parallel-item::after {content: \"\";width: 100%;border-bottom: 1px solid gray;flex-grow: 1;}#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {background-color: #d4ebff;}#sk-container-id-1 div.sk-serial::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: 0;}#sk-container-id-1 div.sk-serial {display: flex;flex-direction: column;align-items: center;background-color: white;padding-right: 0.2em;padding-left: 0.2em;position: relative;}#sk-container-id-1 div.sk-item {position: relative;z-index: 1;}#sk-container-id-1 div.sk-parallel {display: flex;align-items: stretch;justify-content: center;background-color: white;position: relative;}#sk-container-id-1 div.sk-item::before, #sk-container-id-1 div.sk-parallel-item::before {content: \"\";position: absolute;border-left: 1px solid gray;box-sizing: border-box;top: 0;bottom: 0;left: 50%;z-index: -1;}#sk-container-id-1 div.sk-parallel-item {display: flex;flex-direction: column;z-index: 1;position: relative;background-color: white;}#sk-container-id-1 div.sk-parallel-item:first-child::after {align-self: flex-end;width: 50%;}#sk-container-id-1 div.sk-parallel-item:last-child::after {align-self: flex-start;width: 50%;}#sk-container-id-1 div.sk-parallel-item:only-child::after {width: 0;}#sk-container-id-1 div.sk-dashed-wrapped {border: 1px dashed gray;margin: 0 0.4em 0.5em 0.4em;box-sizing: border-box;padding-bottom: 0.4em;background-color: white;}#sk-container-id-1 div.sk-label label {font-family: monospace;font-weight: bold;display: inline-block;line-height: 1.2em;}#sk-container-id-1 div.sk-label-container {text-align: center;}#sk-container-id-1 div.sk-container {/* jupyter's `normalize.less` sets `[hidden] { display: none; }` but bootstrap.min.css set `[hidden] { display: none !important; }` so we also need the `!important` here to be able to override the default hidden behavior on the sphinx rendered scikit-learn.org. See: https://github.com/scikit-learn/scikit-learn/issues/21755 */display: inline-block !important;position: relative;}#sk-container-id-1 div.sk-text-repr-fallback {display: none;}</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>FairGBMClassifier(constraint_fnr_slack=0.05, constraint_type=&#x27;FNR&#x27;,\n",
+       "                  multiplier_learning_rate=0.2, n_estimators=200, n_jobs=-2,\n",
+       "                  random_state=42)</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" checked><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label sk-toggleable__label-arrow\">FairGBMClassifier</label><div class=\"sk-toggleable__content\"><pre>FairGBMClassifier(constraint_fnr_slack=0.05, constraint_type=&#x27;FNR&#x27;,\n",
+       "                  multiplier_learning_rate=0.2, n_estimators=200, n_jobs=-2,\n",
+       "                  random_state=42)</pre></div></div></div></div></div>"
+      ],
+      "text/plain": [
+       "FairGBMClassifier(constraint_fnr_slack=0.05, constraint_type='FNR',\n",
+       "                  multiplier_learning_rate=0.2, n_estimators=200, n_jobs=-2,\n",
+       "                  random_state=42)"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "%%time\n",
+    "# Train using features (X), labels (Y), and sensitive attributes (S)\n",
+    "fairgbm_clf.fit(X_train, Y_train, constraint_group=S_train)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "071ed3c6",
+   "metadata": {},
+   "source": [
+    "### Compute binary predictions\n",
+    "Note that the sensitive attributes are only used in training and not for predicting!"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "id": "12559ea5",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "Y_test_pred = fairgbm_clf.predict(X_test)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "351011ee",
+   "metadata": {},
+   "source": [
+    "### Compute Performance and Fairness metrics"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "id": "cd8fac9c",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from sklearn.metrics import accuracy_score\n",
+    "from utils import compute_fairness_ratio\n",
+    "\n",
+    "acc_val = accuracy_score(Y_test, Y_test_pred)\n",
+    "eq_op_val = compute_fairness_ratio(Y_test, Y_test_pred, S_test, \"TPR\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "id": "1a0c5faa",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "FairGBM:\n",
+      "\tAccuracy: 87.2%\n",
+      "\tFairness: 96.1%\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(f\"FairGBM:\")\n",
+    "print(f\"\\tAccuracy: {acc_val:.1%}\")\n",
+    "print(f\"\\tFairness: {eq_op_val:.1%}\")"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.9.13"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/FairGBM-python-notebooks/requirements.txt b/examples/FairGBM-python-notebooks/requirements.txt
new file mode 100644
index 000000000..e24e82ad8
--- /dev/null
+++ b/examples/FairGBM-python-notebooks/requirements.txt
@@ -0,0 +1,5 @@
+wget
+folktables
+lightgbm~=3.2.1
+scikit-learn
+optuna
\ No newline at end of file
diff --git a/examples/FairGBM-python-notebooks/utils.py b/examples/FairGBM-python-notebooks/utils.py
new file mode 100644
index 000000000..159dfd4b5
--- /dev/null
+++ b/examples/FairGBM-python-notebooks/utils.py
@@ -0,0 +1,167 @@
+"""
+Utility functions to keep the example notebooks uncluttered with boilerplate.
+"""
+import re
+from collections import OrderedDict
+from pathlib import Path
+from typing import Tuple
+
+import numpy as np
+import pandas as pd
+from sklearn.metrics import confusion_matrix
+
+
+DATA_DIR = Path(__file__).parent / "data"
+UCI_ADULT_TARGET_COL = "target"
+UCI_ADULT_SENSITIVE_COL = "sex"
+
+
+def load_uci_adult() -> Tuple[pd.DataFrame, pd.DataFrame]:
+    """Downloads and pre-processes the UCI Adult dataset.
+    
+    Returns
+    -------
+    train_set, test_set : tuple[pd.DataFrame, pd.DataFrame]
+        The pre-processed train and test datasets.
+    """
+    try:
+        import wget
+    except ModuleNotFoundError as err:
+        print(f"Downloading this dataset requires the `wget` python package; got \"{err}\"")
+
+    # URLs for downloading dataset
+    base_url = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/"
+    train_url = base_url + "adult.data"
+    test_url = base_url + "adult.test"
+    names_url = base_url + "adult.names"
+    
+    # Make local data directory
+    DATA_DIR.mkdir(exist_ok=True)
+
+    # Download data
+    train_path = wget.download(train_url, str(DATA_DIR))
+    test_path = wget.download(test_url, str(DATA_DIR))
+    names_path = wget.download(names_url, str(DATA_DIR))
+    
+    return (
+        _preprocess_uci_adult(train_path, names_path),
+        _preprocess_uci_adult(test_path, names_path, skiprows=1),
+    )
+
+
+def _preprocess_uci_adult(data_path, names_path, **read_kwargs) -> pd.DataFrame:
+
+    # Load column names
+    column_map = OrderedDict()
+    line_regexp = re.compile(r"^([-\w]+): (.*)[.]$")
+
+    with open(names_path, "r") as f_in:
+        lines = f_in.readlines()
+        for l in lines:
+            match = line_regexp.match(l)
+            if not match: continue
+
+            col_name = match.group(1)
+            col_values = match.group(2).split(", ")
+            if len(col_values) == 1:
+                col_values = col_values[0]
+
+            column_map[col_name] = col_values
+
+    # Last column is the target
+    column_map[UCI_ADULT_TARGET_COL] = ["<=50K", ">50K"]
+
+    # Load data
+    data = pd.read_csv(
+        data_path,
+        header=None,
+        names=list(column_map.keys()),
+        index_col=None,
+        **read_kwargs)
+
+    # Set correct dtypes
+    data = data.astype({
+        col_name: (
+            float if col_value == "continuous" else "category"
+        ) for col_name, col_value in column_map.items()
+    })
+    
+    # Strip whitespace from categorical values
+    for col in data.columns:
+        if data[col].dtype == "category":
+            data[col] = data[col].map(lambda val: val.strip())            
+
+    # Convert label to numeric
+    data[UCI_ADULT_TARGET_COL] = pd.Series(
+        data=[
+            0 if "<=50K" in val.strip() else 1 
+            for val in data[UCI_ADULT_TARGET_COL]
+        ],
+        dtype=float)
+    return data
+
+
+def split_X_Y_S_uci_adult(data) -> Tuple[pd.DataFrame, pd.Series]:
+    """Splits the given UCI Adult data into features and target.
+    """
+    ignored_cols = [UCI_ADULT_TARGET_COL, UCI_ADULT_SENSITIVE_COL, "fnlwgt"]
+    feature_cols = [col for col in data.columns if col not in ignored_cols]
+
+    X = data[feature_cols]
+    Y = data[UCI_ADULT_TARGET_COL].astype(float)
+    S = pd.Series(
+        data=[1. if val == "Male" else 0. for val in data[UCI_ADULT_SENSITIVE_COL]],
+        dtype=float,)
+    return X, Y, S
+
+
+def compute_fairness_ratio(y_true: np.ndarray, y_pred: np.ndarray, s_true, metric: str) -> float:
+    """Compute fairness metric as the disparity (group-wise ratio)
+    of a given performance metric.
+
+    Parameters
+    ----------
+    y_true : np.ndarray
+        The true labels.
+    y_pred : np.ndarray
+        The binarized predictions.
+    s_true : np.ndarray
+        The sensitive attribute column.
+    metric : str
+        The performance metric used to compute disparity.
+
+    Returns
+    -------
+    value : float
+        The fairness metric value (between 0 and 1).
+    """
+    metric = metric.lower()
+    valid_perf_metrics = ("fpr", "fnr", "tpr", "tnr")
+    
+    def compute_metric(y_true, y_pred):
+        tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()
+        
+        if metric == "fpr":
+            return fp / (fp + tn)
+        elif metric == "tnr":
+            return tn / (fp + tn)
+        elif metric == "fnr":
+            return fn / (fn + tp)
+        elif metric == "tpr":
+            return tp / (fn + tp)
+        else:
+            raise ValueError(f"Invalid metric chosen; must be one of {valid_perf_metrics}; got '{metric}'")
+
+    groupwise_metrics = []
+    for group in pd.Series(s_true).unique():
+        group_filter = (s_true == group)
+        
+        groupwise_metrics.append(compute_metric(
+            y_true[group_filter],
+            y_pred[group_filter],
+        ))
+
+    return min(groupwise_metrics) / max(groupwise_metrics)
+        
+        
+        
\ No newline at end of file
diff --git a/examples/FairGBM/train.conf b/examples/FairGBM/train.conf
index 826dbf949..bac3e215d 100644
--- a/examples/FairGBM/train.conf
+++ b/examples/FairGBM/train.conf
@@ -1,8 +1,8 @@
 # task type, supports train and predict
-task = train
+task=train
 
 # boosting type, support gbdt for now, alias: boosting, boost
-boosting_type = gbdt
+boosting_type=gbdt
 
 # application type, support following application
 # regression , regression task
@@ -10,7 +10,7 @@ boosting_type = gbdt
 # lambdarank , LambdaRank task
 # constrained_cross_entropy , constrained optimization task (classification)
 # alias: application, app
-objective = constrained_cross_entropy   # training FairGBM!
+objective=constrained_cross_entropy   # training FairGBM!
 
 # eval metrics, support multi metric, delimited by ',' , support following metrics
 # l1
@@ -19,45 +19,45 @@ objective = constrained_cross_entropy   # training FairGBM!
 # auc
 # binary_logloss , default metric for binary
 # binary_error
-metric = binary_logloss,auc
+metric=binary_logloss,auc
 
 # frequency for metric output
-metric_freq = 5
+metric_freq=5
 
 # true if need output metric for training data, alias: training_metric, train_metric
-is_training_metric = true
+is_training_metric=true
 
 # training data
 # if existing weight file, should name to "binary.train.weight"
 # alias: train_data, train
-data = BAF-base.train
+data=BAF-base.train
 
 # validation data, support multi validation data, separated by ','
 # if existing weight file, should name to "binary.test.weight"
 # alias: valid, test, test_data,
-valid_data = BAF-base.test
+valid_data=BAF-base.test
 
 # first row has column names
 has_header=True
 
 # name of label column
-label_column = name:fraud_bool
+label_column=name:fraud_bool
 
 # ignore the sensitive attribute column for training (plus the date column)
-ignore_column = name:customer_age_category,month
+ignore_column=name:customer_age_category,month
 
 # all categorical columns
-categorical_column = name:payment_type,employment_status,housing_status,source,device_os
+categorical_column=name:payment_type,employment_status,housing_status,source,device_os
 
 # number of trees(iterations), alias: num_tree, num_iteration, num_iterations, num_round, num_rounds
-num_trees = 1000
+num_trees=1000
 
 # output model file
-output_model = FairGBM_model.txt
+output_model=FairGBM_model.txt
 
 # fixed random state for reproducibility
 # (if multi-threaded may still result in variable results)
-random_state = 42
+random_state=42
 
 #  ** FairGBM-specific parameters **
 # function to use as a differentiable proxy for the step-wise function
diff --git a/examples/README.md b/examples/README.md
index 835bf7b64..9f2e7ec39 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -1,62 +1,127 @@
-Examples
-========
-
-You can learn how to use LightGBM by these examples.
-
-Comments in configuration files might be outdated. Actual information about parameters always can be found [here](https://github.com/microsoft/LightGBM/blob/master/docs/Parameters.rst).
-
-Machine Learning Challenge Winning Solutions
-============================================
-
-**LightGBM is used in many winning solutions, but this table is updated very infrequently.**
-
-| Place         | Competition   | Solution  | Date |
-| ------------- |:------------- | --------- | -----|
-|1st      | [M5 Forecasting - Uncertainty](https://www.kaggle.com/c/m5-forecasting-uncertainty) | [link](https://www.kaggle.com/c/m5-forecasting-uncertainty/discussion/163368) | 2020.7 |
-|3rd      | [M5 Forecasting - Uncertainty](https://www.kaggle.com/c/m5-forecasting-uncertainty) | [link](https://www.kaggle.com/c/m5-forecasting-uncertainty/discussion/166875) | 2020.7 |
-|3rd      | [ALASKA2 Image Steganalysis](https://www.kaggle.com/c/alaska2-image-steganalysis) | [link](https://www.kaggle.com/c/alaska2-image-steganalysis/discussion/168870) | 2020.7 |
-|1st      | [M5 Forecasting - Accuracy](https://www.kaggle.com/c/m5-forecasting-accuracy) | [link](https://www.kaggle.com/c/m5-forecasting-accuracy/discussion/163684) | 2020.6 |
-|2nd      | [COVID19 Global Forecasting (Week 5)](https://www.kaggle.com/c/covid19-global-forecasting-week-5) | [link](https://www.kaggle.com/c/covid19-global-forecasting-week-5/discussion/143893) | 2020.5 |
-|3rd      | [COVID19 Global Forecasting (Week 5)](https://www.kaggle.com/c/covid19-global-forecasting-week-5) | [link](https://www.kaggle.com/c/covid19-global-forecasting-week-5/discussion/143029) | 2020.5 |
-|1st      | [COVID19 Global Forecasting (Week 4)](https://www.kaggle.com/c/covid19-global-forecasting-week-4) | [link](https://www.kaggle.com/c/covid19-global-forecasting-week-5/discussion/154804) | 2020.5 |
-|2nd      | [COVID19 Global Forecasting (Week 4)](https://www.kaggle.com/c/covid19-global-forecasting-week-4) | [link](https://www.kaggle.com/c/covid19-global-forecasting-week-5/discussion/144081) | 2020.5 |
-|2nd      | [2019 Data Science Bowl](https://www.kaggle.com/c/data-science-bowl-2019) | [link](https://www.kaggle.com/c/data-science-bowl-2019/discussion/127388) | 2020.1 |
-| 3rd     | [RSNA Intracranial Hemorrhage Detection](https://www.kaggle.com/c/rsna-intracranial-hemorrhage-detection) | [link](https://www.kaggle.com/c/rsna-intracranial-hemorrhage-detection/discussion/117223#latest-673643) | 2019.11 |
-| 1st     | [IEEE-CIS Fraud Detection](https://www.kaggle.com/c/ieee-fraud-detection) | [link](https://www.kaggle.com/c/ieee-fraud-detection/discussion/111308) | 2019.10 |
-| 2nd     | [IEEE-CIS Fraud Detection](https://www.kaggle.com/c/ieee-fraud-detection) | [link](https://www.kaggle.com/c/ieee-fraud-detection/discussion/111321) | 2019.10 |
-| 2nd     | [Kuzushiji Recognition](https://www.kaggle.com/c/kuzushiji-recognition) | [link](https://www.kaggle.com/c/kuzushiji-recognition/discussion/112712) | 2019.10 |
-| 1st     | [Los Alamos National Laboratory Earthquake Prediction](https://www.kaggle.com/c/LANL-Earthquake-Prediction) | [link](https://www.kaggle.com/c/LANL-Earthquake-Prediction/discussion/94390#latest-632778) | 2019.6 |
-| 3rd     | [Los Alamos National Laboratory Earthquake Prediction](https://www.kaggle.com/c/LANL-Earthquake-Prediction) | [link](https://www.kaggle.com/c/LANL-Earthquake-Prediction/discussion/94459) | 2019.6 |
-| 1st     | [Santander Customer Transaction Prediction](https://www.kaggle.com/c/santander-customer-transaction-prediction) | [link](https://www.kaggle.com/c/santander-customer-transaction-prediction/discussion/89003#latest-678843) | 2019.4 |
-| 2nd     | [Santander Customer Transaction Prediction](https://www.kaggle.com/c/santander-customer-transaction-prediction) | [link](https://www.kaggle.com/c/santander-customer-transaction-prediction/discussion/88939) | 2019.4 |
-| 3rd     | [Santander Customer Transaction Prediction](https://www.kaggle.com/c/santander-customer-transaction-prediction) | [link](https://www.kaggle.com/c/santander-customer-transaction-prediction/discussion/88902) | 2019.4 |
-| 2nd     | [PetFinder.my Adoption Prediction](https://www.kaggle.com/c/petfinder-adoption-prediction) | [link](https://www.kaggle.com/c/petfinder-adoption-prediction/discussion/88773#latest-512090) | 2019.4 |
-| 1st     | [Google Analytics Customer Revenue Prediction](https://www.kaggle.com/c/ga-customer-revenue-prediction) | [link](https://www.kaggle.com/c/ga-customer-revenue-prediction/discussion/82614#latest-482575) | 2019.3  |
-| 1st     | [VSB Power Line Fault Detection](https://www.kaggle.com/c/vsb-power-line-fault-detection) | [link](https://www.kaggle.com/c/vsb-power-line-fault-detection/discussion/87038#latest-521846) | 2019.3 |
-| 5th     | [Elo Merchant Category Recommendation](https://www.kaggle.com/c/elo-merchant-category-recommendation) | [link](https://www.kaggle.com/c/elo-merchant-category-recommendation/discussion/82314#latest-525737) | 2019.2 |
-| 2nd     | [PLAsTiCC Astronomical Classification](https://www.kaggle.com/c/PLAsTiCC-2018) | [link](https://www.kaggle.com/c/PLAsTiCC-2018/discussion/75059#latest-462457) | 2018.12 | 
-| 1st     | [Google Research Doodle Recognition Challenge](https://www.kaggle.com/c/quickdraw-doodle-recognition) | [link](https://www.kaggle.com/c/quickdraw-doodle-recognition/discussion/73738#latest-550028) | 2018.12 |
-| 1st     | [Home Credit Group Home Credit Default Risk](https://www.kaggle.com/c/home-credit-default-risk) | [link](https://www.kaggle.com/c/home-credit-default-risk/discussion/64480#latest-514514) | 2018.8 |
-| 2nd     | [Home Credit Group Home Credit Default Risk](https://www.kaggle.com/c/home-credit-default-risk) | [link](https://www.kaggle.com/c/home-credit-default-risk/discussion/64722#latest-394948) | 2018.8 |
-| 3rd     | [Home Credit Group Home Credit Default Risk](https://www.kaggle.com/c/home-credit-default-risk) | [link](https://www.kaggle.com/c/home-credit-default-risk/discussion/64596#latest-420333) | 2018.8 |
-| 2nd     | [Google AI Open Images - Visual Relationship Track](https://www.kaggle.com/c/google-ai-open-images-visual-relationship-track) | [link](https://www.kaggle.com/c/google-ai-open-images-visual-relationship-track/discussion/64651) | 2018.8 |
-| 2nd     | [Santander Value Prediction Challenge](https://www.kaggle.com/c/santander-value-prediction-challenge) | [link](https://www.kaggle.com/c/santander-value-prediction-challenge/discussion/63848#latest-374826) | 2018.8 |
-| 1st     | [Avito Demand Prediction Challenge](https://www.kaggle.com/c/avito-demand-prediction) | [link](https://www.kaggle.com/c/avito-demand-prediction/discussion/59880#latest-450523) | 2018.6 |
-| 2nd     | [Avito Demand Prediction Challenge](https://www.kaggle.com/c/avito-demand-prediction) | [link](https://www.kaggle.com/c/avito-demand-prediction/discussion/59871#latest-470807) | 2018.6 |
-| 3rd     | [Avito Demand Prediction Challenge](https://www.kaggle.com/c/avito-demand-prediction) | [link](https://www.kaggle.com/c/avito-demand-prediction/discussion/59885#latest-364403) | 2018.6 |
-| 1st     | [TalkingData AdTracking Fraud Detection Challenge](https://www.kaggle.com/c/talkingdata-adtracking-fraud-detection) | [link](https://www.kaggle.com/c/talkingdata-adtracking-fraud-detection/discussion/56475)| 2018.5 |
-| 1st     | [DonorsChoose.org Application Screening](https://www.kaggle.com/c/donorschoose-application-screening)| [link](https://www.kaggle.com/shadowwarrior/1st-place-solution/notebook) | 2018.4 | 
-| 1st     | [Toxic Comment Classification Challenge](https://www.kaggle.com/c/jigsaw-toxic-comment-classification-challenge)| [link](https://www.kaggle.com/c/jigsaw-toxic-comment-classification-challenge/discussion/52557) | 2018.3 |
-| 1st     | [Mercari Price Suggestion Challenge](https://www.kaggle.com/c/mercari-price-suggestion-challenge) | [link](https://www.kaggle.com/c/mercari-price-suggestion-challenge/discussion/50256) | 2018.2 |
-| 1st     | [IEEE's Signal Processing Society, Camera Model Identification](https://www.kaggle.com/c/sp-society-camera-model-identification)| [link](https://www.kaggle.com/c/sp-society-camera-model-identification/discussion/49367) | 2018.2 | 
-| 1st     | [Recruit Restaurant Visitor Forecasting](https://www.kaggle.com/c/recruit-restaurant-visitor-forecasting) | [link](https://www.kaggle.com/pureheart/1st-place-lgb-model-public-0-470-private-0-502/comments) | 2018.2| 
-| 1st     | [WSDM CUP 2018 - KKBox's Music Recommendation Challenge](https://www.kaggle.com/c/kkbox-music-recommendation-challenge) | [link](https://www.kaggle.com/c/kkbox-music-recommendation-challenge/discussion/45942) | 2017.12 |
-| 1st     | [Porto Seguro’s Safe Driver Prediction](https://www.kaggle.com/c/porto-seguro-safe-driver-prediction) | [link](https://www.kaggle.com/c/porto-seguro-safe-driver-prediction/discussion/44629) |2017.11 |
-| 1st     | [Quora Question Pairs](https://www.kaggle.com/c/quora-question-pairs) | [link](https://www.kaggle.com/c/quora-question-pairs/discussion/34355) | 2017.6 |
-| 1st     | [Two Sigma Connect: Rental Listing Inquiries](https://www.kaggle.com/c/two-sigma-connect-rental-listing-inquiries) | [link](https://www.kaggle.com/c/two-sigma-connect-rental-listing-inquiries/discussion/32163) | 2017.4 |
-| 1st     | [CIKM2017 AnalytiCup - Lazada Product Title Quality Challenge](http://cikm2017.org/CIKM_AnalytiCup_task3.html) | [link](http://cikm2017.org/download/analytiCup/session3/CIKMAnalytiCup2017_LazadaProductTitleQuality_T3.pdf) | 2017.9 |
-| 2nd     | [Two Sigma Connect: Rental Listing Inquiries](https://www.kaggle.com/c/two-sigma-connect-rental-listing-inquiries) | [link](https://www.kaggle.com/c/two-sigma-connect-rental-listing-inquiries/discussion/32148) | 2017.4 |
-| 3rd     | [Two Sigma Connect: Rental Listing Inquiries](https://www.kaggle.com/c/two-sigma-connect-rental-listing-inquiries) | [link](https://www.kaggle.com/c/two-sigma-connect-rental-listing-inquiries/discussion/32123) | 2017.4 |
-| 3rd     | [Dogs vs. Cats Redux: Kernels Edition](https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition) | [link](http://blog.kaggle.com/2017/04/20/dogs-vs-cats-redux-playground-competition-3rd-place-interview-marco-lugo) | - |
-| 3rd     | [Bosch Production Line Performance](https://www.kaggle.com/c/bosch-production-line-performance) | [link](http://blog.kaggle.com/2016/12/15/bosch-production-line-performance-competition-winners-interview-3rd-place-team-data-property-avengers-darragh-marios-mathias-stanislav) | 2016.11 |
-| 1st     | [The 1st Di-Tech Competitions](http://research.xiaojukeji.com/competition/main.action?competitionId=DiTech2016) | - | 2016.7 |
+# FairGBM Usage Examples
+
+Just as with [vanilla LightGBM](https://github.com/microsoft/LightGBM/tree/master/examples), you can use FairGBM in multiple ways:
+1. Using the Python API (**_recommended_**)
+1. Using the command line (and config files)
+1. Using the C API
+
+## Using Python
+
+Several Python examples available in the [_notebooks folder_](FairGBM-python-notebooks)!.
+
+**[Recommended]** Using the sklearn-style API:
+
+```python
+from fairgbm import FairGBMClassifier
+
+# Instantiate
+fairgbm_clf = FairGBMClassifier(
+    constraint_type="FNR",    # constraint on equal group-wise TPR (equal opportunity)
+    n_estimators=200,         # core parameters from vanilla LightGBM
+    random_state=42,          # ...
+)
+
+# Train using features (X), labels (Y), and sensitive attributes (S)
+fairgbm_clf.fit(X, Y, constraint_group=S)
+
+# Predict
+Y_test_pred = fairgbm_clf.predict_proba(X_test)[:, -1]  # Compute continuous class probabilities (recommended)
+# Y_test_pred = fairgbm_clf.predict(X_test)             # Or compute discrete class predictions
+```
+
+
+Or using the standard LightGBM API:
+
+```python
+from fairgbm import Dataset, train
+
+# Create train dataset with features (X), labels (Y), and sensitive attributes (S)
+train_set = Dataset(X, label=Y, constraint_group=S)
+
+# Example FairGBM parameters
+fgbm_params = {
+    "objective": "constrained_cross_entropy",   # This objective is FairGBM's entry-point
+    "constraint_type": "FNR",   # Constraint on equal group-wise TPR (equal opportunity)
+    "n_estimators": 200,
+    "random_state": 42,
+}
+
+# Train FairGBM
+fairgbm_clf = train(params=fgbm_params, train_set=train_set)
+
+# Compute test predictions
+y_test_pred = fairgbm_clf.predict(X_test)
+# NOTE! FairGBM doesn't use sensitive attributes (S_test) to predict
+```
+
+
+## Using the command line
+
+To run FairGBM from the command line, you'll need to compile the project locally
+```
+git clone --recurse-submodules https://github.com/feedzai/fairgbm.git
+cd fairgbm
+cmake .
+make -j4
+```
+
+and then call the compiled binary with your config file
+```
+"./lightgbm" config=your_config_file.txt
+```
+
+you can also add other parameters right from the command line
+```
+"./lightgbm" config=train.conf objective=constrained_cross_entropy
+```
+
+For further details see LightGBM's guide on [compiling locally](https://lightgbm.readthedocs.io/en/latest/Installation-Guide.html#installation-guide) and [running from the command line](https://lightgbm.readthedocs.io/en/latest/Quick-Start.html#run-lightgbm).
+
+
+## Using the C API
+> Using the C API is only recommended for interoperability with other languages. 
+> See [this repository](https://github.com/feedzai/feedzai-openml-java/blob/master/openml-lightgbm/lightgbm-provider/src/main/java/com/feedzai/openml/provider/lightgbm/LightGBMBinaryClassificationModelTrainer.java#L126) 
+> for an example on training FairGBM/LightGBM from a Java code-base.
+
+This is a barebones example of using FairGBM with the LightGBM C API.
+For further details please consult LightGBM's [C API reference](https://lightgbm.readthedocs.io/en/latest/C-API.html).
+
+```c
+int main(int argc, char** argv) {
+
+    // Construct dataset
+    LightGBM::DatasetHandle datasetHandle;
+    std::string datasetParameters = (
+            "label_column=name:fraud_bool "
+            "constraint_group_column=name:customer_age_category "
+            "has_header=True");
+    LightGBM::LGBM_DatasetCreateFromFile("examples/FairGBM/BAF-base.train", datasetParameters, &datasetHandle);
+    
+    // Construct GBM model
+    LightGBM::BoosterHandle boosterHandle;
+    std::string boosterParameters = ("objective=constrained_cross_entropy constraint_type=fpr");  // Add other parameters as needed
+    LightGBM::LGBM_BoosterCreate(datasetHandle, parameters, &boosterHandle)
+    
+    // Train model
+    int isFinished, numIterations = 100;
+    for (int trainIteration = 0; trainIteration < numIterations; ++trainIteration) {
+        int returnCodeLGBM = LightGBM::LGBM_BoosterUpdateOneIter(boosterHandle, &isFinished);
+    }
+}
+```
+
+If you're interested in looking under the proverbial C++ hood, you should start from the 
+[`ConstrainedObjectiveFunction`](/include/LightGBM/constrained_objective_function.h) class.
+Most FairGBM-specific classes are in the C++ namespace `LightGBM::Constrained`.
+
+
+## Configuration files
+
+FairGBM's config files functionality is forked from LightGBM.
+Please consult [LightGBM's core parameters](https://lightgbm.readthedocs.io/en/latest/Parameters.html#core-parameters) 
+to see how to set-up a config file.
+
+Example FairGBM config files [here](/examples/FairGBM/train.conf) or [here](/examples/FairGBM-other/train.conf).
+
+**Note**: Remember that to use the FairGBM classifier you must always set `objective=constrained_cross_entropy`.
+This is not needed when using the Python `FairGBMClassifier` class as it's already taken care of.
diff --git a/include/LightGBM/constrained_objective_function.h b/include/LightGBM/constrained_objective_function.h
index 578672a10..bb4164bc1 100644
--- a/include/LightGBM/constrained_objective_function.h
+++ b/include/LightGBM/constrained_objective_function.h
@@ -1,10 +1,22 @@
 /**
- * The copyright of this file belongs to Feedzai. The file cannot be
- * reproduced in whole or in part, stored in a retrieval system,
- * transmitted in any form, or by any means electronic, mechanical,
- * photocopying, or otherwise, without the prior permission of the owner.
+ * Copyright 2022 Feedzai
  *
- * (c) 2022 Feedzai, Strictly Confidential
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
 
 #ifndef LIGHTGBM_CONSTRAINED_OBJECTIVE_FUNCTION_H_
diff --git a/include/LightGBM/proxy_losses/base.hpp b/include/LightGBM/proxy_losses/base.hpp
index 802c82fc3..5b68d8bb1 100644
--- a/include/LightGBM/proxy_losses/base.hpp
+++ b/include/LightGBM/proxy_losses/base.hpp
@@ -1,10 +1,22 @@
 /**
- * The copyright of this file belongs to Feedzai. The file cannot be
- * reproduced in whole or in part, stored in a retrieval system,
- * transmitted in any form, or by any means electronic, mechanical,
- * photocopying, or otherwise, without the prior permission of the owner.
+ * Copyright 2022 Feedzai
  *
- * (c) 2022 Feedzai, Strictly Confidential
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
 
 #ifndef LIGHTGBM_PROXY_LOSSES_BASE_HPP_
diff --git a/include/LightGBM/proxy_losses/hinge.hpp b/include/LightGBM/proxy_losses/hinge.hpp
index 249f11221..4f06f5728 100644
--- a/include/LightGBM/proxy_losses/hinge.hpp
+++ b/include/LightGBM/proxy_losses/hinge.hpp
@@ -1,10 +1,22 @@
 /**
- * The copyright of this file belongs to Feedzai. The file cannot be
- * reproduced in whole or in part, stored in a retrieval system,
- * transmitted in any form, or by any means electronic, mechanical,
- * photocopying, or otherwise, without the prior permission of the owner.
+ * Copyright 2022 Feedzai
  *
- * (c) 2022 Feedzai, Strictly Confidential
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
 
 #ifndef LIGHTGBM_PROXY_LOSSES_HINGE_HPP_
diff --git a/include/LightGBM/proxy_losses/proxy_loss_factory.hpp b/include/LightGBM/proxy_losses/proxy_loss_factory.hpp
index df971297f..8dbaf0c81 100644
--- a/include/LightGBM/proxy_losses/proxy_loss_factory.hpp
+++ b/include/LightGBM/proxy_losses/proxy_loss_factory.hpp
@@ -1,10 +1,22 @@
 /**
- * The copyright of this file belongs to Feedzai. The file cannot be
- * reproduced in whole or in part, stored in a retrieval system,
- * transmitted in any form, or by any means electronic, mechanical,
- * photocopying, or otherwise, without the prior permission of the owner.
+ * Copyright 2022 Feedzai
  *
- * (c) 2022 Feedzai, Strictly Confidential
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
 
 #ifndef LIGHTGBM_PROXY_LOSSES_PROXY_LOSS_FACTORY_HPP_
diff --git a/include/LightGBM/proxy_losses/quadratic.hpp b/include/LightGBM/proxy_losses/quadratic.hpp
index 541f302ae..d49b8403c 100644
--- a/include/LightGBM/proxy_losses/quadratic.hpp
+++ b/include/LightGBM/proxy_losses/quadratic.hpp
@@ -1,10 +1,22 @@
 /**
- * The copyright of this file belongs to Feedzai. The file cannot be
- * reproduced in whole or in part, stored in a retrieval system,
- * transmitted in any form, or by any means electronic, mechanical,
- * photocopying, or otherwise, without the prior permission of the owner.
+ * Copyright 2022 Feedzai
  *
- * (c) 2022 Feedzai, Strictly Confidential
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
 
 #ifndef LIGHTGBM_PROXY_LOSSES_QUADRATIC_HPP_
diff --git a/include/LightGBM/proxy_losses/xentropy.hpp b/include/LightGBM/proxy_losses/xentropy.hpp
index 80ebdf0c5..cf7674f27 100644
--- a/include/LightGBM/proxy_losses/xentropy.hpp
+++ b/include/LightGBM/proxy_losses/xentropy.hpp
@@ -1,10 +1,22 @@
 /**
- * The copyright of this file belongs to Feedzai. The file cannot be
- * reproduced in whole or in part, stored in a retrieval system,
- * transmitted in any form, or by any means electronic, mechanical,
- * photocopying, or otherwise, without the prior permission of the owner.
+ * Copyright 2022 Feedzai
  *
- * (c) 2022 Feedzai, Strictly Confidential
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
 
 #ifndef LIGHTGBM_PROXY_LOSSES_XENTROPY_HPP_
diff --git a/include/LightGBM/utils/constrained.hpp b/include/LightGBM/utils/constrained.hpp
index 6110da56e..1d88acd7f 100644
--- a/include/LightGBM/utils/constrained.hpp
+++ b/include/LightGBM/utils/constrained.hpp
@@ -1,12 +1,23 @@
 /**
- * The copyright of this file belongs to Feedzai. The file cannot be
- * reproduced in whole or in part, stored in a retrieval system,
- * transmitted in any form, or by any means electronic, mechanical,
- * photocopying, or otherwise, without the prior permission of the owner.
+ * Copyright 2022 Feedzai
  *
- * (c) 2021 Feedzai, Strictly Confidential
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 #ifndef LIGHTGBM_UTILS_CONSTRAINED_HPP_
 #define LIGHTGBM_UTILS_CONSTRAINED_HPP_
 
diff --git a/pmml/README.md b/pmml/README.md
deleted file mode 100644
index d69996c8e..000000000
--- a/pmml/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-PMML Generator 
-==============
-
-The old Python convert script is removed due to it cannot support the new format of categorical features.
-
-Please refer to https://github.com/jpmml/jpmml-lightgbm.
diff --git a/python-package/fairgbm/VERSION.txt b/python-package/fairgbm/VERSION.txt
index 3ca4a7207..6f060dcbc 100644
--- a/python-package/fairgbm/VERSION.txt
+++ b/python-package/fairgbm/VERSION.txt
@@ -1,1 +1,1 @@
-3.2.1.99
+0.9.9
\ No newline at end of file
diff --git a/src/io/config_auto.cpp b/src/io/config_auto.cpp
index 964eaf94c..329a82389 100644
--- a/src/io/config_auto.cpp
+++ b/src/io/config_auto.cpp
@@ -168,6 +168,8 @@ const std::unordered_map<std::string, std::string>& Config::alias_table() {
   {"nodes", "machines"},
 
   // FairGBM parameters
+  {"groupwise_constraint_type", "constraint_type"},
+  {"fairness_constraint_type", "constraint_type"},
   {"lagrangian_learning_rate", "multiplier_learning_rate"},
   {"lagrangian_multiplier_learning_rate", "multiplier_learning_rate"},
   {"init_lagrange_multipliers", "init_lagrangian_multipliers"},
diff --git a/src/objective/constrained_recall_objective.hpp b/src/objective/constrained_recall_objective.hpp
index 6edb17f7b..00f9bdadc 100644
--- a/src/objective/constrained_recall_objective.hpp
+++ b/src/objective/constrained_recall_objective.hpp
@@ -1,10 +1,22 @@
 /**
- * The copyright of this file belongs to Feedzai. The file cannot be
- * reproduced in whole or in part, stored in a retrieval system,
- * transmitted in any form, or by any means electronic, mechanical,
- * photocopying, or otherwise, without the prior permission of the owner.
+ * Copyright 2022 Feedzai
  *
- * (c) 2021 Feedzai, Strictly Confidential
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
 /*!
  * Constrained proxy recall objective (minimize proxy FNR).
diff --git a/src/objective/constrained_xentropy_objective.hpp b/src/objective/constrained_xentropy_objective.hpp
index 5762c60a5..836a802b7 100644
--- a/src/objective/constrained_xentropy_objective.hpp
+++ b/src/objective/constrained_xentropy_objective.hpp
@@ -1,10 +1,22 @@
 /**
- * The copyright of this file belongs to Feedzai. The file cannot be
- * reproduced in whole or in part, stored in a retrieval system,
- * transmitted in any form, or by any means electronic, mechanical,
- * photocopying, or otherwise, without the prior permission of the owner.
+ * Copyright 2022 Feedzai
  *
- * (c) 2021 Feedzai, Strictly Confidential
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
 /*!
  * Copyright (c) 2017 Microsoft Corporation. All rights reserved.
diff --git a/src/proxy_losses/proxy_loss_factory.cpp b/src/proxy_losses/proxy_loss_factory.cpp
index bb37bbb35..1e5b4adf5 100644
--- a/src/proxy_losses/proxy_loss_factory.cpp
+++ b/src/proxy_losses/proxy_loss_factory.cpp
@@ -1,10 +1,22 @@
 /**
- * The copyright of this file belongs to Feedzai. The file cannot be
- * reproduced in whole or in part, stored in a retrieval system,
- * transmitted in any form, or by any means electronic, mechanical,
- * photocopying, or otherwise, without the prior permission of the owner.
+ * Copyright 2022 Feedzai
  *
- * (c) 2022 Feedzai, Strictly Confidential
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
 
 #include <LightGBM/proxy_losses/proxy_loss_factory.hpp>


Test patch:
diff --git a/R-package/data/agaricus.test.rda b/R-package/data/agaricus.test.rda
deleted file mode 100644
index ad8d50af7..000000000
Binary files a/R-package/data/agaricus.test.rda and /dev/null differ
diff --git a/R-package/man/agaricus.test.Rd b/R-package/man/agaricus.test.Rd
deleted file mode 100644
index aad4627ee..000000000
--- a/R-package/man/agaricus.test.Rd
+++ /dev/null
@@ -1,31 +0,0 @@
-% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/lightgbm.R
-\docType{data}
-\name{agaricus.test}
-\alias{agaricus.test}
-\title{Test part from Mushroom Data Set}
-\format{
-A list containing a label vector, and a dgCMatrix object with 1611
-rows and 126 variables
-}
-\usage{
-data(agaricus.test)
-}
-\description{
-This data set is originally from the Mushroom data set,
-             UCI Machine Learning Repository.
-             This data set includes the following fields:
-
-             \itemize{
-                 \item{\code{label}: the label for each record}
-                 \item{\code{data}: a sparse Matrix of \code{dgCMatrix} class, with 126 columns.}
-             }
-}
-\references{
-https://archive.ics.uci.edu/ml/datasets/Mushroom
-
-Bache, K. & Lichman, M. (2013). UCI Machine Learning Repository
-[http://archive.ics.uci.edu/ml]. Irvine, CA: University of California,
-School of Information and Computer Science.
-}
-\keyword{datasets}
diff --git a/R-package/tests/testthat.R b/R-package/tests/testthat.R
deleted file mode 100644
index 4a1d1268d..000000000
--- a/R-package/tests/testthat.R
+++ /dev/null
@@ -1,8 +0,0 @@
-library(testthat)
-library(lightgbm)
-
-test_check(
-    package = "lightgbm"
-    , stop_on_failure = TRUE
-    , stop_on_warning = FALSE
-)
diff --git a/R-package/tests/testthat/test_Predictor.R b/R-package/tests/testthat/test_Predictor.R
deleted file mode 100644
index 77719f236..000000000
--- a/R-package/tests/testthat/test_Predictor.R
+++ /dev/null
@@ -1,78 +0,0 @@
-context("Predictor")
-
-test_that("predictions do not fail for integer input", {
-    X <- as.matrix(as.integer(iris[, "Species"]), ncol = 1L)
-    y <- iris[["Sepal.Length"]]
-    dtrain <- lgb.Dataset(X, label = y)
-    fit <- lgb.train(
-        data = dtrain
-        , objective = "regression"
-        , verbose = -1L
-        , nrounds = 3L
-    )
-    X_double <- X[c(1L, 51L, 101L), , drop = FALSE]
-    X_integer <- X_double
-    storage.mode(X_double) <- "double"
-    pred_integer <- predict(fit, X_integer)
-    pred_double <- predict(fit, X_double)
-    expect_equal(pred_integer, pred_double)
-})
-
-test_that("start_iteration works correctly", {
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    data(agaricus.test, package = "lightgbm")
-    train <- agaricus.train
-    test <- agaricus.test
-    dtrain <- lgb.Dataset(
-        agaricus.train$data
-        , label = agaricus.train$label
-    )
-    dtest <- lgb.Dataset.create.valid(
-        dtrain
-        , agaricus.test$data
-        , label = agaricus.test$label
-    )
-    bst <- lightgbm(
-        data = as.matrix(train$data)
-        , label = train$label
-        , num_leaves = 4L
-        , learning_rate = 0.6
-        , nrounds = 50L
-        , objective = "binary"
-        , valids = list("test" = dtest)
-        , early_stopping_rounds = 2L
-    )
-    expect_true(lgb.is.Booster(bst))
-    pred1 <- predict(bst, data = test$data, rawscore = TRUE)
-    pred_contrib1 <- predict(bst, test$data, predcontrib = TRUE)
-    pred2 <- rep(0.0, length(pred1))
-    pred_contrib2 <- rep(0.0, length(pred2))
-    step <- 11L
-    end_iter <- 49L
-    if (bst$best_iter != -1L) {
-        end_iter <- bst$best_iter - 1L
-    }
-    start_iters <- seq(0L, end_iter, by = step)
-    for (start_iter in start_iters) {
-        n_iter <- min(c(end_iter - start_iter + 1L, step))
-        inc_pred <- predict(bst, test$data
-            , start_iteration = start_iter
-            , num_iteration = n_iter
-            , rawscore = TRUE
-        )
-        inc_pred_contrib <- bst$predict(test$data
-            , start_iteration = start_iter
-            , num_iteration = n_iter
-            , predcontrib = TRUE
-        )
-        pred2 <- pred2 + inc_pred
-        pred_contrib2 <- pred_contrib2 + inc_pred_contrib
-    }
-    expect_equal(pred2, pred1)
-    expect_equal(pred_contrib2, pred_contrib1)
-
-    pred_leaf1 <- predict(bst, test$data, predleaf = TRUE)
-    pred_leaf2 <- predict(bst, test$data, start_iteration = 0L, num_iteration = end_iter + 1L, predleaf = TRUE)
-    expect_equal(pred_leaf1, pred_leaf2)
-})
diff --git a/R-package/tests/testthat/test_basic.R b/R-package/tests/testthat/test_basic.R
deleted file mode 100644
index a49c728d2..000000000
--- a/R-package/tests/testthat/test_basic.R
+++ /dev/null
@@ -1,2044 +0,0 @@
-context("lightgbm()")
-
-ON_WINDOWS <- .Platform$OS.type == "windows"
-
-UTF8_LOCALE <- all(grepl(
-  pattern = "UTF-8$"
-  , x = Sys.getlocale(category = "LC_CTYPE")
-))
-
-data(agaricus.train, package = "lightgbm")
-data(agaricus.test, package = "lightgbm")
-train <- agaricus.train
-test <- agaricus.test
-
-TOLERANCE <- 1e-6
-set.seed(708L)
-
-# [description] Every time this function is called, it adds 0.1
-#               to an accumulator then returns the current value.
-#               This is used to mock the situation where an evaluation
-#               metric increases every iteration
-ACCUMULATOR_NAME <- "INCREASING_METRIC_ACUMULATOR"
-assign(x = ACCUMULATOR_NAME, value = 0.0, envir = .GlobalEnv)
-
-.increasing_metric <- function(preds, dtrain) {
-  if (!exists(ACCUMULATOR_NAME, envir = .GlobalEnv)) {
-    assign(ACCUMULATOR_NAME, 0.0, envir = .GlobalEnv)
-  }
-  assign(
-    x = ACCUMULATOR_NAME
-    , value = get(ACCUMULATOR_NAME, envir = .GlobalEnv) + 0.1
-    , envir = .GlobalEnv
-  )
-  return(list(
-    name = "increasing_metric"
-    , value = get(ACCUMULATOR_NAME, envir = .GlobalEnv)
-    , higher_better = TRUE
-  ))
-}
-
-# [description] Evaluation function that always returns the
-#               same value
-CONSTANT_METRIC_VALUE <- 0.2
-.constant_metric <- function(preds, dtrain) {
-  return(list(
-    name = "constant_metric"
-    , value = CONSTANT_METRIC_VALUE
-    , higher_better = FALSE
-  ))
-}
-
-# sample datasets to test early stopping
-DTRAIN_RANDOM_REGRESSION <- lgb.Dataset(
-  data = as.matrix(rnorm(100L), ncol = 1L, drop = FALSE)
-  , label = rnorm(100L)
-)
-DVALID_RANDOM_REGRESSION <- lgb.Dataset(
-  data = as.matrix(rnorm(50L), ncol = 1L, drop = FALSE)
-  , label = rnorm(50L)
-)
-DTRAIN_RANDOM_CLASSIFICATION <- lgb.Dataset(
-  data = as.matrix(rnorm(120L), ncol = 1L, drop = FALSE)
-  , label = sample(c(0L, 1L), size = 120L, replace = TRUE)
-)
-DVALID_RANDOM_CLASSIFICATION <- lgb.Dataset(
-  data = as.matrix(rnorm(37L), ncol = 1L, drop = FALSE)
-  , label = sample(c(0L, 1L), size = 37L, replace = TRUE)
-)
-
-test_that("train and predict binary classification", {
-  nrounds <- 10L
-  bst <- lightgbm(
-    data = train$data
-    , label = train$label
-    , num_leaves = 5L
-    , nrounds = nrounds
-    , objective = "binary"
-    , metric = "binary_error"
-    , save_name = tempfile(fileext = ".model")
-  )
-  expect_false(is.null(bst$record_evals))
-  record_results <- lgb.get.eval.result(bst, "train", "binary_error")
-  expect_lt(min(record_results), 0.02)
-
-  pred <- predict(bst, test$data)
-  expect_equal(length(pred), 1611L)
-
-  pred1 <- predict(bst, train$data, num_iteration = 1L)
-  expect_equal(length(pred1), 6513L)
-  err_pred1 <- sum((pred1 > 0.5) != train$label) / length(train$label)
-  err_log <- record_results[1L]
-  expect_lt(abs(err_pred1 - err_log), TOLERANCE)
-})
-
-
-test_that("train and predict softmax", {
-  set.seed(708L)
-  lb <- as.numeric(iris$Species) - 1L
-
-  bst <- lightgbm(
-    data = as.matrix(iris[, -5L])
-    , label = lb
-    , num_leaves = 4L
-    , learning_rate = 0.05
-    , nrounds = 20L
-    , min_data = 20L
-    , min_hessian = 10.0
-    , objective = "multiclass"
-    , metric = "multi_error"
-    , num_class = 3L
-    , save_name = tempfile(fileext = ".model")
-  )
-
-  expect_false(is.null(bst$record_evals))
-  record_results <- lgb.get.eval.result(bst, "train", "multi_error")
-  expect_lt(min(record_results), 0.06)
-
-  pred <- predict(bst, as.matrix(iris[, -5L]))
-  expect_equal(length(pred), nrow(iris) * 3L)
-})
-
-
-test_that("use of multiple eval metrics works", {
-  metrics <- list("binary_error", "auc", "binary_logloss")
-  bst <- lightgbm(
-    data = train$data
-    , label = train$label
-    , num_leaves = 4L
-    , learning_rate = 1.0
-    , nrounds = 10L
-    , objective = "binary"
-    , metric = metrics
-    , save_name = tempfile(fileext = ".model")
-  )
-  expect_false(is.null(bst$record_evals))
-  expect_named(
-    bst$record_evals[["train"]]
-    , unlist(metrics)
-    , ignore.order = FALSE
-    , ignore.case = FALSE
-  )
-})
-
-test_that("lgb.Booster.upper_bound() and lgb.Booster.lower_bound() work as expected for binary classification", {
-  set.seed(708L)
-  nrounds <- 10L
-  bst <- lightgbm(
-    data = train$data
-    , label = train$label
-    , num_leaves = 5L
-    , nrounds = nrounds
-    , objective = "binary"
-    , metric = "binary_error"
-    , save_name = tempfile(fileext = ".model")
-  )
-  expect_true(abs(bst$lower_bound() - -1.590853) < TOLERANCE)
-  expect_true(abs(bst$upper_bound() - 1.871015) <  TOLERANCE)
-})
-
-test_that("lgb.Booster.upper_bound() and lgb.Booster.lower_bound() work as expected for regression", {
-  set.seed(708L)
-  nrounds <- 10L
-  bst <- lightgbm(
-    data = train$data
-    , label = train$label
-    , num_leaves = 5L
-    , nrounds = nrounds
-    , objective = "regression"
-    , metric = "l2"
-    , save_name = tempfile(fileext = ".model")
-  )
-  expect_true(abs(bst$lower_bound() - 0.1513859) < TOLERANCE)
-  expect_true(abs(bst$upper_bound() - 0.9080349) < TOLERANCE)
-})
-
-test_that("lightgbm() rejects negative or 0 value passed to nrounds", {
-  dtrain <- lgb.Dataset(train$data, label = train$label)
-  params <- list(objective = "regression", metric = "l2,l1")
-  for (nround_value in c(-10L, 0L)) {
-    expect_error({
-      bst <- lightgbm(
-        data = dtrain
-        , params = params
-        , nrounds = nround_value
-        , save_name = tempfile(fileext = ".model")
-      )
-    }, "nrounds should be greater than zero")
-  }
-})
-
-test_that("lightgbm() performs evaluation on validation sets if they are provided", {
-  set.seed(708L)
-  dvalid1 <- lgb.Dataset(
-    data = train$data
-    , label = train$label
-  )
-  dvalid2 <- lgb.Dataset(
-    data = train$data
-    , label = train$label
-  )
-  nrounds <- 10L
-  bst <- lightgbm(
-    data = train$data
-    , label = train$label
-    , num_leaves = 5L
-    , nrounds = nrounds
-    , objective = "binary"
-    , metric = c(
-      "binary_error"
-      , "auc"
-    )
-    , valids = list(
-      "valid1" = dvalid1
-      , "valid2" = dvalid2
-    )
-    , save_name = tempfile(fileext = ".model")
-  )
-
-  expect_named(
-    bst$record_evals
-    , c("train", "valid1", "valid2", "start_iter")
-    , ignore.order = TRUE
-    , ignore.case = FALSE
-  )
-  for (valid_name in c("train", "valid1", "valid2")) {
-    eval_results <- bst$record_evals[[valid_name]][["binary_error"]]
-    expect_length(eval_results[["eval"]], nrounds)
-  }
-  expect_true(abs(bst$record_evals[["train"]][["binary_error"]][["eval"]][[1L]] - 0.02226317) < TOLERANCE)
-  expect_true(abs(bst$record_evals[["valid1"]][["binary_error"]][["eval"]][[1L]] - 0.02226317) < TOLERANCE)
-  expect_true(abs(bst$record_evals[["valid2"]][["binary_error"]][["eval"]][[1L]] - 0.02226317) < TOLERANCE)
-})
-
-
-context("training continuation")
-
-test_that("training continuation works", {
-  dtrain <- lgb.Dataset(
-    train$data
-    , label = train$label
-    , free_raw_data = FALSE
-  )
-  watchlist <- list(train = dtrain)
-  param <- list(
-    objective = "binary"
-    , metric = "binary_logloss"
-    , num_leaves = 5L
-    , learning_rate = 1.0
-  )
-
-  # train for 10 consecutive iterations
-  bst <- lgb.train(param, dtrain, nrounds = 10L, watchlist)
-  err_bst <- lgb.get.eval.result(bst, "train", "binary_logloss", 10L)
-
-  #  train for 5 iterations, save, load, train for 5 more
-  bst1 <- lgb.train(param, dtrain, nrounds = 5L, watchlist)
-  model_file <- tempfile(fileext = ".model")
-  lgb.save(bst1, model_file)
-  bst2 <- lgb.train(param, dtrain, nrounds = 5L, watchlist, init_model = bst1)
-  err_bst2 <- lgb.get.eval.result(bst2, "train", "binary_logloss", 10L)
-
-  # evaluation metrics should be nearly identical for the model trained in 10 coonsecutive
-  # iterations and the one trained in 5-then-5.
-  expect_lt(abs(err_bst - err_bst2), 0.01)
-})
-
-context("lgb.cv()")
-
-test_that("cv works", {
-  dtrain <- lgb.Dataset(train$data, label = train$label)
-  params <- list(objective = "regression", metric = "l2,l1")
-  bst <- lgb.cv(
-    params
-    , dtrain
-    , 10L
-    , nfold = 5L
-    , min_data = 1L
-    , learning_rate = 1.0
-    , early_stopping_rounds = 10L
-  )
-  expect_false(is.null(bst$record_evals))
-})
-
-test_that("lgb.cv() rejects negative or 0 value passed to nrounds", {
-  dtrain <- lgb.Dataset(train$data, label = train$label)
-  params <- list(objective = "regression", metric = "l2,l1")
-  for (nround_value in c(-10L, 0L)) {
-    expect_error({
-      bst <- lgb.cv(
-        params
-        , dtrain
-        , nround_value
-        , nfold = 5L
-        , min_data = 1L
-      )
-    }, "nrounds should be greater than zero")
-  }
-})
-
-test_that("lgb.cv() throws an informative error is 'data' is not an lgb.Dataset and labels are not given", {
-  bad_values <- list(
-    4L
-    , "hello"
-    , list(a = TRUE, b = seq_len(10L))
-    , data.frame(x = seq_len(5L), y = seq_len(5L))
-    , data.table::data.table(x = seq_len(5L),  y = seq_len(5L))
-    , matrix(data = seq_len(10L), 2L, 5L)
-  )
-  for (val in bad_values) {
-    expect_error({
-      bst <- lgb.cv(
-        params = list(objective = "regression", metric = "l2,l1")
-        , data = val
-        , 10L
-        , nfold = 5L
-        , min_data = 1L
-      )
-    }, regexp = "'label' must be provided for lgb.cv if 'data' is not an 'lgb.Dataset'", fixed = TRUE)
-  }
-})
-
-test_that("lightgbm.cv() gives the correct best_score and best_iter for a metric where higher values are better", {
-  set.seed(708L)
-  dtrain <- lgb.Dataset(
-    data = as.matrix(runif(n = 500L, min = 0.0, max = 15.0), drop = FALSE)
-    , label = rep(c(0L, 1L), 250L)
-  )
-  nrounds <- 10L
-  cv_bst <- lgb.cv(
-    data = dtrain
-    , nfold = 5L
-    , nrounds = nrounds
-    , num_leaves = 5L
-    , params = list(
-      objective = "binary"
-      , metric = "auc,binary_error"
-      , learning_rate = 1.5
-    )
-  )
-  expect_is(cv_bst, "lgb.CVBooster")
-  expect_named(
-    cv_bst$record_evals
-    , c("start_iter", "valid")
-    , ignore.order = FALSE
-    , ignore.case = FALSE
-  )
-  auc_scores <- unlist(cv_bst$record_evals[["valid"]][["auc"]][["eval"]])
-  expect_length(auc_scores, nrounds)
-  expect_identical(cv_bst$best_iter, which.max(auc_scores))
-  expect_identical(cv_bst$best_score, auc_scores[which.max(auc_scores)])
-})
-
-test_that("lgb.cv() fit on linearly-relatead data improves when using linear learners", {
-  set.seed(708L)
-  .new_dataset <- function() {
-    X <- matrix(rnorm(1000L), ncol = 1L)
-    return(lgb.Dataset(
-      data = X
-      , label = 2L * X + runif(nrow(X), 0L, 0.1)
-    ))
-  }
-
-  params <- list(
-    objective = "regression"
-    , verbose = -1L
-    , metric = "mse"
-    , seed = 0L
-    , num_leaves = 2L
-  )
-
-  dtrain <- .new_dataset()
-  cv_bst <- lgb.cv(
-    data = dtrain
-    , nrounds = 10L
-    , params = params
-    , nfold = 5L
-  )
-  expect_is(cv_bst, "lgb.CVBooster")
-
-  dtrain <- .new_dataset()
-  cv_bst_linear <- lgb.cv(
-    data = dtrain
-    , nrounds = 10L
-    , params = modifyList(params, list(linear_tree = TRUE))
-    , nfold = 5L
-  )
-  expect_is(cv_bst_linear, "lgb.CVBooster")
-
-  expect_true(cv_bst_linear$best_score < cv_bst$best_score)
-})
-
-context("lgb.train()")
-
-test_that("lgb.train() works as expected with multiple eval metrics", {
-  metrics <- c("binary_error", "auc", "binary_logloss")
-  bst <- lgb.train(
-    data = lgb.Dataset(
-      train$data
-      , label = train$label
-    )
-    , learning_rate = 1.0
-    , nrounds = 10L
-    , params = list(
-      objective = "binary"
-      , metric = metrics
-    )
-    , valids = list(
-      "train" = lgb.Dataset(
-        train$data
-        , label = train$label
-      )
-    )
-  )
-  expect_false(is.null(bst$record_evals))
-  expect_named(
-    bst$record_evals[["train"]]
-    , unlist(metrics)
-    , ignore.order = FALSE
-    , ignore.case = FALSE
-  )
-})
-
-test_that("lgb.train() rejects negative or 0 value passed to nrounds", {
-  dtrain <- lgb.Dataset(train$data, label = train$label)
-  params <- list(objective = "regression", metric = "l2,l1")
-  for (nround_value in c(-10L, 0L)) {
-    expect_error({
-      bst <- lgb.train(
-        params
-        , dtrain
-        , nround_value
-      )
-    }, "nrounds should be greater than zero")
-  }
-})
-
-test_that("lgb.train() throws an informative error if 'data' is not an lgb.Dataset", {
-  bad_values <- list(
-    4L
-    , "hello"
-    , list(a = TRUE, b = seq_len(10L))
-    , data.frame(x = seq_len(5L), y = seq_len(5L))
-    , data.table::data.table(x = seq_len(5L),  y = seq_len(5L))
-    , matrix(data = seq_len(10L), 2L, 5L)
-  )
-  for (val in bad_values) {
-    expect_error({
-      bst <- lgb.train(
-        params = list(objective = "regression", metric = "l2,l1")
-        , data = val
-        , 10L
-      )
-    }, regexp = "data must be an lgb.Dataset instance", fixed = TRUE)
-  }
-})
-
-test_that("lgb.train() throws an informative error if 'valids' is not a list of lgb.Dataset objects", {
-  valids <- list(
-    "valid1" = data.frame(x = rnorm(5L), y = rnorm(5L))
-    , "valid2" = data.frame(x = rnorm(5L), y = rnorm(5L))
-  )
-  expect_error({
-    bst <- lgb.train(
-      params = list(objective = "regression", metric = "l2,l1")
-      , data = lgb.Dataset(train$data, label = train$label)
-      , 10L
-      , valids = valids
-    )
-  }, regexp = "valids must be a list of lgb.Dataset elements")
-})
-
-test_that("lgb.train() errors if 'valids' is a list of lgb.Dataset objects but some do not have names", {
-  valids <- list(
-    "valid1" = lgb.Dataset(matrix(rnorm(10L), 5L, 2L))
-    , lgb.Dataset(matrix(rnorm(10L), 2L, 5L))
-  )
-  expect_error({
-    bst <- lgb.train(
-      params = list(objective = "regression", metric = "l2,l1")
-      , data = lgb.Dataset(train$data, label = train$label)
-      , 10L
-      , valids = valids
-    )
-  }, regexp = "each element of valids must have a name")
-})
-
-test_that("lgb.train() throws an informative error if 'valids' contains lgb.Dataset objects but none have names", {
-  valids <- list(
-    lgb.Dataset(matrix(rnorm(10L), 5L, 2L))
-    , lgb.Dataset(matrix(rnorm(10L), 2L, 5L))
-  )
-  expect_error({
-    bst <- lgb.train(
-      params = list(objective = "regression", metric = "l2,l1")
-      , data = lgb.Dataset(train$data, label = train$label)
-      , 10L
-      , valids = valids
-    )
-  }, regexp = "each element of valids must have a name")
-})
-
-test_that("lgb.train() works with force_col_wise and force_row_wise", {
-  set.seed(1234L)
-  nrounds <- 10L
-  dtrain <- lgb.Dataset(
-    train$data
-    , label = train$label
-  )
-  params <- list(
-    objective = "binary"
-    , metric = "binary_error"
-    , force_col_wise = TRUE
-  )
-  bst_col_wise <- lgb.train(
-    params = params
-    , data = dtrain
-    , nrounds = nrounds
-  )
-
-  params <- list(
-    objective = "binary"
-    , metric = "binary_error"
-    , force_row_wise = TRUE
-  )
-  bst_row_wise <- lgb.train(
-    params = params
-    , data = dtrain
-    , nrounds = nrounds
-  )
-
-  expected_error <- 0.003070782
-  expect_equal(bst_col_wise$eval_train()[[1L]][["value"]], expected_error)
-  expect_equal(bst_row_wise$eval_train()[[1L]][["value"]], expected_error)
-
-  # check some basic details of the boosters just to be sure force_col_wise
-  # and force_row_wise are not causing any weird side effects
-  for (bst in list(bst_row_wise, bst_col_wise)) {
-    expect_equal(bst$current_iter(), nrounds)
-    parsed_model <- jsonlite::fromJSON(bst$dump_model())
-    expect_equal(parsed_model$objective, "binary sigmoid:1")
-    expect_false(parsed_model$average_output)
-  }
-})
-
-test_that("lgb.train() works as expected with sparse features", {
-  set.seed(708L)
-  num_obs <- 70000L
-  trainDF <- data.frame(
-    y = sample(c(0L, 1L), size = num_obs, replace = TRUE)
-    , x = sample(c(1.0:10.0, rep(NA_real_, 50L)), size = num_obs, replace = TRUE)
-  )
-  dtrain <- lgb.Dataset(
-    data = as.matrix(trainDF[["x"]], drop = FALSE)
-    , label = trainDF[["y"]]
-  )
-  nrounds <- 1L
-  bst <- lgb.train(
-    params = list(
-      objective = "binary"
-      , min_data = 1L
-      , min_data_in_bin = 1L
-    )
-    , data = dtrain
-    , nrounds = nrounds
-  )
-
-  expect_true(lgb.is.Booster(bst))
-  expect_equal(bst$current_iter(), nrounds)
-  parsed_model <- jsonlite::fromJSON(bst$dump_model())
-  expect_equal(parsed_model$objective, "binary sigmoid:1")
-  expect_false(parsed_model$average_output)
-  expected_error <- 0.6931268
-  expect_true(abs(bst$eval_train()[[1L]][["value"]] - expected_error) < TOLERANCE)
-})
-
-test_that("lgb.train() works with early stopping for classification", {
-  trainDF <- data.frame(
-    "feat1" = rep(c(5.0, 10.0), 500L)
-    , "target" = rep(c(0L, 1L), 500L)
-  )
-  validDF <- data.frame(
-    "feat1" = rep(c(5.0, 10.0), 50L)
-    , "target" = rep(c(0L, 1L), 50L)
-  )
-  dtrain <- lgb.Dataset(
-    data = as.matrix(trainDF[["feat1"]], drop = FALSE)
-    , label = trainDF[["target"]]
-  )
-  dvalid <- lgb.Dataset(
-    data = as.matrix(validDF[["feat1"]], drop = FALSE)
-    , label = validDF[["target"]]
-  )
-  nrounds <- 10L
-
-  ################################
-  # train with no early stopping #
-  ################################
-  bst <- lgb.train(
-    params = list(
-      objective = "binary"
-      , metric = "binary_error"
-    )
-    , data = dtrain
-    , nrounds = nrounds
-    , valids = list(
-      "valid1" = dvalid
-    )
-  )
-
-  # a perfect model should be trivial to obtain, but all 10 rounds
-  # should happen
-  expect_equal(bst$best_score, 0.0)
-  expect_equal(bst$best_iter, 1L)
-  expect_equal(length(bst$record_evals[["valid1"]][["binary_error"]][["eval"]]), nrounds)
-
-  #############################
-  # train with early stopping #
-  #############################
-  early_stopping_rounds <- 5L
-  bst  <- lgb.train(
-    params = list(
-      objective = "binary"
-      , metric = "binary_error"
-      , early_stopping_rounds = early_stopping_rounds
-    )
-    , data = dtrain
-    , nrounds = nrounds
-    , valids = list(
-      "valid1" = dvalid
-    )
-  )
-
-  # a perfect model should be trivial to obtain, and only 6 rounds
-  # should have happen (1 with improvement, 5 consecutive with no improvement)
-  expect_equal(bst$best_score, 0.0)
-  expect_equal(bst$best_iter, 1L)
-  expect_equal(
-    length(bst$record_evals[["valid1"]][["binary_error"]][["eval"]])
-    , early_stopping_rounds + 1L
-  )
-
-})
-
-test_that("lgb.train() treats early_stopping_rounds<=0 as disabling early stopping", {
-  set.seed(708L)
-  trainDF <- data.frame(
-    "feat1" = rep(c(5.0, 10.0), 500L)
-    , "target" = rep(c(0L, 1L), 500L)
-  )
-  validDF <- data.frame(
-    "feat1" = rep(c(5.0, 10.0), 50L)
-    , "target" = rep(c(0L, 1L), 50L)
-  )
-  dtrain <- lgb.Dataset(
-    data = as.matrix(trainDF[["feat1"]], drop = FALSE)
-    , label = trainDF[["target"]]
-  )
-  dvalid <- lgb.Dataset(
-    data = as.matrix(validDF[["feat1"]], drop = FALSE)
-    , label = validDF[["target"]]
-  )
-  nrounds <- 5L
-
-  for (value in c(-5L, 0L)) {
-
-    #----------------------------#
-    # passed as keyword argument #
-    #----------------------------#
-    bst <- lgb.train(
-      params = list(
-        objective = "binary"
-        , metric = "binary_error"
-      )
-      , data = dtrain
-      , nrounds = nrounds
-      , valids = list(
-        "valid1" = dvalid
-      )
-      , early_stopping_rounds = value
-    )
-
-    # a perfect model should be trivial to obtain, but all 10 rounds
-    # should happen
-    expect_equal(bst$best_score, 0.0)
-    expect_equal(bst$best_iter, 1L)
-    expect_equal(length(bst$record_evals[["valid1"]][["binary_error"]][["eval"]]), nrounds)
-
-    #---------------------------#
-    # passed as parameter alias #
-    #---------------------------#
-    bst <- lgb.train(
-      params = list(
-        objective = "binary"
-        , metric = "binary_error"
-        , n_iter_no_change = value
-      )
-      , data = dtrain
-      , nrounds = nrounds
-      , valids = list(
-        "valid1" = dvalid
-      )
-    )
-
-    # a perfect model should be trivial to obtain, but all 10 rounds
-    # should happen
-    expect_equal(bst$best_score, 0.0)
-    expect_equal(bst$best_iter, 1L)
-    expect_equal(length(bst$record_evals[["valid1"]][["binary_error"]][["eval"]]), nrounds)
-  }
-})
-
-test_that("lgb.train() works with early stopping for classification with a metric that should be maximized", {
-  set.seed(708L)
-  dtrain <- lgb.Dataset(
-    data = train$data
-    , label = train$label
-  )
-  dvalid <- lgb.Dataset(
-    data = test$data
-    , label = test$label
-  )
-  nrounds <- 10L
-
-  #############################
-  # train with early stopping #
-  #############################
-  early_stopping_rounds <- 5L
-  # the harsh max_depth guarantees that AUC improves over at least the first few iterations
-  bst_auc  <- lgb.train(
-    params = list(
-      objective = "binary"
-      , metric = "auc"
-      , max_depth = 3L
-      , early_stopping_rounds = early_stopping_rounds
-    )
-    , data = dtrain
-    , nrounds = nrounds
-    , valids = list(
-      "valid1" = dvalid
-    )
-  )
-  bst_binary_error  <- lgb.train(
-    params = list(
-      objective = "binary"
-      , metric = "binary_error"
-      , max_depth = 3L
-      , early_stopping_rounds = early_stopping_rounds
-    )
-    , data = dtrain
-    , nrounds = nrounds
-    , valids = list(
-      "valid1" = dvalid
-    )
-  )
-
-  # early stopping should have been hit for binary_error (higher_better = FALSE)
-  eval_info <- bst_binary_error$.__enclos_env__$private$get_eval_info()
-  expect_identical(eval_info, "binary_error")
-  expect_identical(
-    unname(bst_binary_error$.__enclos_env__$private$higher_better_inner_eval)
-    , FALSE
-  )
-  expect_identical(bst_binary_error$best_iter, 1L)
-  expect_identical(bst_binary_error$current_iter(), early_stopping_rounds + 1L)
-  expect_true(abs(bst_binary_error$best_score - 0.01613904) < TOLERANCE)
-
-  # early stopping should not have been hit for AUC (higher_better = TRUE)
-  eval_info <- bst_auc$.__enclos_env__$private$get_eval_info()
-  expect_identical(eval_info, "auc")
-  expect_identical(
-    unname(bst_auc$.__enclos_env__$private$higher_better_inner_eval)
-    , TRUE
-  )
-  expect_identical(bst_auc$best_iter, 9L)
-  expect_identical(bst_auc$current_iter(), nrounds)
-  expect_true(abs(bst_auc$best_score - 0.9999969) < TOLERANCE)
-})
-
-test_that("lgb.train() works with early stopping for regression", {
-  set.seed(708L)
-  trainDF <- data.frame(
-    "feat1" = rep(c(10.0, 100.0), 500L)
-    , "target" = rep(c(-50.0, 50.0), 500L)
-  )
-  validDF <- data.frame(
-    "feat1" = rep(50.0, 4L)
-    , "target" = rep(50.0, 4L)
-  )
-  dtrain <- lgb.Dataset(
-    data = as.matrix(trainDF[["feat1"]], drop = FALSE)
-    , label = trainDF[["target"]]
-  )
-  dvalid <- lgb.Dataset(
-    data = as.matrix(validDF[["feat1"]], drop = FALSE)
-    , label = validDF[["target"]]
-  )
-  nrounds <- 10L
-
-  ################################
-  # train with no early stopping #
-  ################################
-  bst <- lgb.train(
-    params = list(
-      objective = "regression"
-      , metric = "rmse"
-    )
-    , data = dtrain
-    , nrounds = nrounds
-    , valids = list(
-      "valid1" = dvalid
-    )
-  )
-
-  # the best possible model should come from the first iteration, but
-  # all 10 training iterations should happen
-  expect_equal(bst$best_score, 55.0)
-  expect_equal(bst$best_iter, 1L)
-  expect_equal(length(bst$record_evals[["valid1"]][["rmse"]][["eval"]]), nrounds)
-
-  #############################
-  # train with early stopping #
-  #############################
-  early_stopping_rounds <- 5L
-  bst  <- lgb.train(
-    params = list(
-      objective = "regression"
-      , metric = "rmse"
-      , early_stopping_rounds = early_stopping_rounds
-    )
-    , data = dtrain
-    , nrounds = nrounds
-    , valids = list(
-      "valid1" = dvalid
-    )
-  )
-
-  # the best model should be from the first iteration, and only 6 rounds
-  # should have happen (1 with improvement, 5 consecutive with no improvement)
-  expect_equal(bst$best_score, 55.0)
-  expect_equal(bst$best_iter, 1L)
-  expect_equal(
-    length(bst$record_evals[["valid1"]][["rmse"]][["eval"]])
-    , early_stopping_rounds + 1L
-  )
-})
-
-test_that("lgb.train() does not stop early if early_stopping_rounds is not given", {
-  set.seed(708L)
-
-  increasing_metric_starting_value <- get(
-    ACCUMULATOR_NAME
-    , envir = .GlobalEnv
-  )
-  nrounds <- 10L
-  metrics <- list(
-    .constant_metric
-    , .increasing_metric
-  )
-  bst <- lgb.train(
-    params = list(
-      objective = "regression"
-      , metric = "None"
-    )
-    , data = DTRAIN_RANDOM_REGRESSION
-    , nrounds = nrounds
-    , valids = list("valid1" = DVALID_RANDOM_REGRESSION)
-    , eval = metrics
-  )
-
-  # Only the two functions provided to "eval" should have been evaluated
-  expect_equal(length(bst$record_evals[["valid1"]]), 2L)
-
-  # all 10 iterations should have happen, and the best_iter should be
-  # the first one (based on constant_metric)
-  best_iter <- 1L
-  expect_equal(bst$best_iter, best_iter)
-
-  # best_score should be taken from the first metric
-  expect_equal(
-    bst$best_score
-    , bst$record_evals[["valid1"]][["constant_metric"]][["eval"]][[best_iter]]
-  )
-
-  # early stopping should not have happened. Even though constant_metric
-  # had 9 consecutive iterations with no improvement, it is ignored because of
-  # first_metric_only = TRUE
-  expect_equal(
-    length(bst$record_evals[["valid1"]][["constant_metric"]][["eval"]])
-    , nrounds
-  )
-  expect_equal(
-    length(bst$record_evals[["valid1"]][["increasing_metric"]][["eval"]])
-    , nrounds
-  )
-})
-
-test_that("If first_metric_only is not given or is FALSE, lgb.train() decides to stop early based on all metrics", {
-  set.seed(708L)
-
-  early_stopping_rounds <- 3L
-  param_variations <- list(
-    list(
-      objective = "regression"
-      , metric = "None"
-      , early_stopping_rounds = early_stopping_rounds
-    )
-    , list(
-      objective = "regression"
-      , metric = "None"
-      , early_stopping_rounds = early_stopping_rounds
-      , first_metric_only = FALSE
-    )
-  )
-
-  for (params in param_variations) {
-
-    nrounds <- 10L
-    bst <- lgb.train(
-      params = params
-      , data = DTRAIN_RANDOM_REGRESSION
-      , nrounds = nrounds
-      , valids = list(
-        "valid1" = DVALID_RANDOM_REGRESSION
-      )
-      , eval = list(
-        .increasing_metric
-        , .constant_metric
-      )
-    )
-
-    # Only the two functions provided to "eval" should have been evaluated
-    expect_equal(length(bst$record_evals[["valid1"]]), 2L)
-
-    # early stopping should have happened, and should have stopped early_stopping_rounds + 1 rounds in
-    # because constant_metric never improves
-    #
-    # the best iteration should be the last one, because increasing_metric was first
-    # and gets better every iteration
-    best_iter <- early_stopping_rounds + 1L
-    expect_equal(bst$best_iter, best_iter)
-
-    # best_score should be taken from "increasing_metric" because it was first
-    expect_equal(
-      bst$best_score
-      , bst$record_evals[["valid1"]][["increasing_metric"]][["eval"]][[best_iter]]
-    )
-
-    # early stopping should not have happened. even though increasing_metric kept
-    # getting better, early stopping should have happened because "constant_metric"
-    # did not improve
-    expect_equal(
-      length(bst$record_evals[["valid1"]][["constant_metric"]][["eval"]])
-      , early_stopping_rounds + 1L
-    )
-    expect_equal(
-      length(bst$record_evals[["valid1"]][["increasing_metric"]][["eval"]])
-      , early_stopping_rounds + 1L
-    )
-  }
-
-})
-
-test_that("If first_metric_only is TRUE, lgb.train() decides to stop early based on only the first metric", {
-  set.seed(708L)
-  nrounds <- 10L
-  early_stopping_rounds <- 3L
-  increasing_metric_starting_value <- get(ACCUMULATOR_NAME, envir = .GlobalEnv)
-  bst <- lgb.train(
-    params = list(
-      objective = "regression"
-      , metric = "None"
-      , early_stopping_rounds = early_stopping_rounds
-      , first_metric_only = TRUE
-    )
-    , data = DTRAIN_RANDOM_REGRESSION
-    , nrounds = nrounds
-    , valids = list(
-      "valid1" = DVALID_RANDOM_REGRESSION
-    )
-    , eval = list(
-      .increasing_metric
-      , .constant_metric
-    )
-  )
-
-  # Only the two functions provided to "eval" should have been evaluated
-  expect_equal(length(bst$record_evals[["valid1"]]), 2L)
-
-  # all 10 iterations should happen, and the best_iter should be the final one
-  expect_equal(bst$best_iter, nrounds)
-
-  # best_score should be taken from "increasing_metric"
-  expect_equal(
-    bst$best_score
-    , increasing_metric_starting_value + 0.1 * nrounds
-  )
-
-  # early stopping should not have happened. Even though constant_metric
-  # had 9 consecutive iterations with no improvement, it is ignored because of
-  # first_metric_only = TRUE
-  expect_equal(
-    length(bst$record_evals[["valid1"]][["constant_metric"]][["eval"]])
-    , nrounds
-  )
-  expect_equal(
-    length(bst$record_evals[["valid1"]][["increasing_metric"]][["eval"]])
-    , nrounds
-  )
-})
-
-test_that("lgb.train() works when a mixture of functions and strings are passed to eval", {
-  set.seed(708L)
-  nrounds <- 10L
-  increasing_metric_starting_value <- get(ACCUMULATOR_NAME, envir = .GlobalEnv)
-  bst <- lgb.train(
-    params = list(
-      objective = "regression"
-      , metric = "None"
-    )
-    , data = DTRAIN_RANDOM_REGRESSION
-    , nrounds = nrounds
-    , valids = list(
-      "valid1" = DVALID_RANDOM_REGRESSION
-    )
-    , eval = list(
-      .increasing_metric
-      , "rmse"
-      , .constant_metric
-      , "l2"
-    )
-  )
-
-  # all 4 metrics should have been used
-  expect_named(
-    bst$record_evals[["valid1"]]
-    , expected = c("rmse", "l2", "increasing_metric", "constant_metric")
-    , ignore.order = TRUE
-    , ignore.case = FALSE
-  )
-
-  # the difference metrics shouldn't have been mixed up with each other
-  results <- bst$record_evals[["valid1"]]
-  expect_true(abs(results[["rmse"]][["eval"]][[1L]] - 1.105012) < TOLERANCE)
-  expect_true(abs(results[["l2"]][["eval"]][[1L]] - 1.221051) < TOLERANCE)
-  expected_increasing_metric <- increasing_metric_starting_value + 0.1
-  expect_true(
-    abs(
-      results[["increasing_metric"]][["eval"]][[1L]] - expected_increasing_metric
-    ) < TOLERANCE
-  )
-  expect_true(abs(results[["constant_metric"]][["eval"]][[1L]] - CONSTANT_METRIC_VALUE) < TOLERANCE)
-
-})
-
-test_that("lgb.train() works when a list of strings or a character vector is passed to eval", {
-
-  # testing list and character vector, as well as length-1 and length-2
-  eval_variations <- list(
-    c("binary_error", "binary_logloss")
-    , "binary_logloss"
-    , list("binary_error", "binary_logloss")
-    , list("binary_logloss")
-  )
-
-  for (eval_variation in eval_variations) {
-
-    set.seed(708L)
-    nrounds <- 10L
-    increasing_metric_starting_value <- get(ACCUMULATOR_NAME, envir = .GlobalEnv)
-    bst <- lgb.train(
-      params = list(
-        objective = "binary"
-        , metric = "None"
-      )
-      , data = DTRAIN_RANDOM_CLASSIFICATION
-      , nrounds = nrounds
-      , valids = list(
-        "valid1" = DVALID_RANDOM_CLASSIFICATION
-      )
-      , eval = eval_variation
-    )
-
-    # both metrics should have been used
-    expect_named(
-      bst$record_evals[["valid1"]]
-      , expected = unlist(eval_variation)
-      , ignore.order = TRUE
-      , ignore.case = FALSE
-    )
-
-    # the difference metrics shouldn't have been mixed up with each other
-    results <- bst$record_evals[["valid1"]]
-    if ("binary_error" %in% unlist(eval_variation)) {
-      expect_true(abs(results[["binary_error"]][["eval"]][[1L]] - 0.4864865) < TOLERANCE)
-    }
-    if ("binary_logloss" %in% unlist(eval_variation)) {
-      expect_true(abs(results[["binary_logloss"]][["eval"]][[1L]] - 0.6932548) < TOLERANCE)
-    }
-  }
-})
-
-test_that("lgb.train() works when you specify both 'metric' and 'eval' with strings", {
-  set.seed(708L)
-  nrounds <- 10L
-  increasing_metric_starting_value <- get(ACCUMULATOR_NAME, envir = .GlobalEnv)
-  bst <- lgb.train(
-    params = list(
-      objective = "binary"
-      , metric = "binary_error"
-    )
-    , data = DTRAIN_RANDOM_CLASSIFICATION
-    , nrounds = nrounds
-    , valids = list(
-      "valid1" = DVALID_RANDOM_CLASSIFICATION
-    )
-    , eval = "binary_logloss"
-  )
-
-  # both metrics should have been used
-  expect_named(
-    bst$record_evals[["valid1"]]
-    , expected = c("binary_error", "binary_logloss")
-    , ignore.order = TRUE
-    , ignore.case = FALSE
-  )
-
-  # the difference metrics shouldn't have been mixed up with each other
-  results <- bst$record_evals[["valid1"]]
-  expect_true(abs(results[["binary_error"]][["eval"]][[1L]] - 0.4864865) < TOLERANCE)
-  expect_true(abs(results[["binary_logloss"]][["eval"]][[1L]] - 0.6932548) < TOLERANCE)
-})
-
-test_that("lgb.train() works when you give a function for eval", {
-  set.seed(708L)
-  nrounds <- 10L
-  increasing_metric_starting_value <- get(ACCUMULATOR_NAME, envir = .GlobalEnv)
-  bst <- lgb.train(
-    params = list(
-      objective = "binary"
-      , metric = "None"
-    )
-    , data = DTRAIN_RANDOM_CLASSIFICATION
-    , nrounds = nrounds
-    , valids = list(
-      "valid1" = DVALID_RANDOM_CLASSIFICATION
-    )
-    , eval = .constant_metric
-  )
-
-  # the difference metrics shouldn't have been mixed up with each other
-  results <- bst$record_evals[["valid1"]]
-  expect_true(abs(results[["constant_metric"]][["eval"]][[1L]] - CONSTANT_METRIC_VALUE) < TOLERANCE)
-})
-
-test_that("lgb.train() works with early stopping for regression with a metric that should be minimized", {
-  set.seed(708L)
-  trainDF <- data.frame(
-    "feat1" = rep(c(10.0, 100.0), 500L)
-    , "target" = rep(c(-50.0, 50.0), 500L)
-  )
-  validDF <- data.frame(
-    "feat1" = rep(50.0, 4L)
-    , "target" = rep(50.0, 4L)
-  )
-  dtrain <- lgb.Dataset(
-    data = as.matrix(trainDF[["feat1"]], drop = FALSE)
-    , label = trainDF[["target"]]
-  )
-  dvalid <- lgb.Dataset(
-    data = as.matrix(validDF[["feat1"]], drop = FALSE)
-    , label = validDF[["target"]]
-  )
-  nrounds <- 10L
-
-  #############################
-  # train with early stopping #
-  #############################
-  early_stopping_rounds <- 5L
-  bst  <- lgb.train(
-    params = list(
-      objective = "regression"
-      , metric = c(
-          "mape"
-          , "rmse"
-          , "mae"
-      )
-      , min_data_in_bin = 5L
-      , early_stopping_rounds = early_stopping_rounds
-    )
-    , data = dtrain
-    , nrounds = nrounds
-    , valids = list(
-      "valid1" = dvalid
-    )
-  )
-
-  # the best model should be from the first iteration, and only 6 rounds
-  # should have happened (1 with improvement, 5 consecutive with no improvement)
-  expect_equal(bst$best_score, 1.1)
-  expect_equal(bst$best_iter, 1L)
-  expect_equal(
-    length(bst$record_evals[["valid1"]][["mape"]][["eval"]])
-    , early_stopping_rounds + 1L
-  )
-
-  # Booster should understand thatt all three of these metrics should be minimized
-  eval_info <- bst$.__enclos_env__$private$get_eval_info()
-  expect_identical(eval_info, c("mape", "rmse", "l1"))
-  expect_identical(
-    unname(bst$.__enclos_env__$private$higher_better_inner_eval)
-    , rep(FALSE, 3L)
-  )
-})
-
-
-test_that("lgb.train() supports non-ASCII feature names", {
-  dtrain <- lgb.Dataset(
-    data = matrix(rnorm(400L), ncol =  4L)
-    , label = rnorm(100L)
-  )
-  feature_names <- c("F_零", "F_一", "F_二", "F_三")
-  bst <- lgb.train(
-    data = dtrain
-    , nrounds = 5L
-    , obj = "regression"
-    , params = list(
-      metric = "rmse"
-    )
-    , colnames = feature_names
-  )
-  expect_true(lgb.is.Booster(bst))
-  dumped_model <- jsonlite::fromJSON(bst$dump_model())
-
-  # UTF-8 strings are not well-supported on Windows
-  # * https://developer.r-project.org/Blog/public/2020/05/02/utf-8-support-on-windows/
-  # * https://developer.r-project.org/Blog/public/2020/07/30/windows/utf-8-build-of-r-and-cran-packages/index.html
-  if (UTF8_LOCALE && !ON_WINDOWS) {
-    expect_identical(
-      dumped_model[["feature_names"]]
-      , feature_names
-    )
-  } else {
-    expect_identical(
-      dumped_model[["feature_names"]]
-      , iconv(feature_names, to = "UTF-8")
-    )
-  }
-})
-
-test_that("lgb.train() works with integer, double, and numeric data", {
-  data(mtcars)
-  X <- as.matrix(mtcars[, -1L])
-  y <- mtcars[, 1L, drop = TRUE]
-  expected_mae <- 4.263667
-  for (data_mode in c("numeric", "double", "integer")) {
-    mode(X) <- data_mode
-    nrounds <- 10L
-    bst <- lightgbm(
-      data = X
-      , label = y
-      , params = list(
-        objective = "regression"
-        , min_data = 1L
-        , learning_rate = 0.01
-        , seed = 708L
-      )
-      , nrounds = nrounds
-    )
-
-    # should have trained for 10 iterations and found splits
-    modelDT <- lgb.model.dt.tree(bst)
-    expect_equal(modelDT[, max(tree_index)], nrounds - 1L)
-    expect_gt(nrow(modelDT), nrounds * 3L)
-
-    # should have achieved expected performance
-    preds <- predict(bst, X)
-    mae <- mean(abs(y - preds))
-    expect_true(abs(mae - expected_mae) < TOLERANCE)
-  }
-})
-
-test_that("when early stopping is not activated, best_iter and best_score come from valids and not training data", {
-  set.seed(708L)
-  trainDF <- data.frame(
-    "feat1" = rep(c(10.0, 100.0), 500L)
-    , "target" = rep(c(-50.0, 50.0), 500L)
-  )
-  validDF <- data.frame(
-    "feat1" = rep(50.0, 4L)
-    , "target" = rep(50.0, 4L)
-  )
-  dtrain <- lgb.Dataset(
-    data = as.matrix(trainDF[["feat1"]], drop = FALSE)
-    , label = trainDF[["target"]]
-  )
-  dvalid1 <- lgb.Dataset(
-    data = as.matrix(validDF[["feat1"]], drop = FALSE)
-    , label = validDF[["target"]]
-  )
-  dvalid2 <- lgb.Dataset(
-    data = as.matrix(validDF[1L:10L, "feat1"], drop = FALSE)
-    , label = validDF[1L:10L, "target"]
-  )
-  nrounds <- 10L
-  train_params <- list(
-    objective = "regression"
-    , metric = "rmse"
-    , learning_rate = 1.5
-  )
-
-  # example 1: two valids, neither are the training data
-  bst <- lgb.train(
-    data = dtrain
-    , nrounds = nrounds
-    , num_leaves = 5L
-    , valids = list(
-      "valid1" = dvalid1
-      , "valid2" = dvalid2
-    )
-    , params = train_params
-  )
-  expect_named(
-    bst$record_evals
-    , c("start_iter", "valid1", "valid2")
-    , ignore.order = FALSE
-    , ignore.case = FALSE
-  )
-  rmse_scores <- unlist(bst$record_evals[["valid1"]][["rmse"]][["eval"]])
-  expect_length(rmse_scores, nrounds)
-  expect_identical(bst$best_iter, which.min(rmse_scores))
-  expect_identical(bst$best_score, rmse_scores[which.min(rmse_scores)])
-
-  # example 2: train first (called "train") and two valids
-  bst <- lgb.train(
-    data = dtrain
-    , nrounds = nrounds
-    , num_leaves = 5L
-    , valids = list(
-      "train" = dtrain
-      , "valid1" = dvalid1
-      , "valid2" = dvalid2
-    )
-    , params = train_params
-  )
-  expect_named(
-    bst$record_evals
-    , c("start_iter", "train", "valid1", "valid2")
-    , ignore.order = FALSE
-    , ignore.case = FALSE
-  )
-  rmse_scores <- unlist(bst$record_evals[["valid1"]][["rmse"]][["eval"]])
-  expect_length(rmse_scores, nrounds)
-  expect_identical(bst$best_iter, which.min(rmse_scores))
-  expect_identical(bst$best_score, rmse_scores[which.min(rmse_scores)])
-
-  # example 3: train second (called "train") and two valids
-  bst <- lgb.train(
-    data = dtrain
-    , nrounds = nrounds
-    , num_leaves = 5L
-    , valids = list(
-      "valid1" = dvalid1
-      , "train" = dtrain
-      , "valid2" = dvalid2
-    )
-    , params = train_params
-  )
-  # note that "train" still ends up as the first one
-  expect_named(
-    bst$record_evals
-    , c("start_iter", "train", "valid1", "valid2")
-    , ignore.order = FALSE
-    , ignore.case = FALSE
-  )
-  rmse_scores <- unlist(bst$record_evals[["valid1"]][["rmse"]][["eval"]])
-  expect_length(rmse_scores, nrounds)
-  expect_identical(bst$best_iter, which.min(rmse_scores))
-  expect_identical(bst$best_score, rmse_scores[which.min(rmse_scores)])
-
-  # example 4: train third (called "train") and two valids
-  bst <- lgb.train(
-    data = dtrain
-    , nrounds = nrounds
-    , num_leaves = 5L
-    , valids = list(
-      "valid1" = dvalid1
-      , "valid2" = dvalid2
-      , "train" = dtrain
-    )
-    , params = train_params
-  )
-  # note that "train" still ends up as the first one
-  expect_named(
-    bst$record_evals
-    , c("start_iter", "train", "valid1", "valid2")
-    , ignore.order = FALSE
-    , ignore.case = FALSE
-  )
-  rmse_scores <- unlist(bst$record_evals[["valid1"]][["rmse"]][["eval"]])
-  expect_length(rmse_scores, nrounds)
-  expect_identical(bst$best_iter, which.min(rmse_scores))
-  expect_identical(bst$best_score, rmse_scores[which.min(rmse_scores)])
-
-  # example 5: train second (called "something-random-we-would-not-hardcode") and two valids
-  bst <- lgb.train(
-    data = dtrain
-    , nrounds = nrounds
-    , num_leaves = 5L
-    , valids = list(
-      "valid1" = dvalid1
-      , "something-random-we-would-not-hardcode" = dtrain
-      , "valid2" = dvalid2
-    )
-    , params = train_params
-  )
-  # note that "something-random-we-would-not-hardcode" was recognized as the training
-  # data even though it isn't named "train"
-  expect_named(
-    bst$record_evals
-    , c("start_iter", "something-random-we-would-not-hardcode", "valid1", "valid2")
-    , ignore.order = FALSE
-    , ignore.case = FALSE
-  )
-  rmse_scores <- unlist(bst$record_evals[["valid1"]][["rmse"]][["eval"]])
-  expect_length(rmse_scores, nrounds)
-  expect_identical(bst$best_iter, which.min(rmse_scores))
-  expect_identical(bst$best_score, rmse_scores[which.min(rmse_scores)])
-
-  # example 6: the only valid supplied is the training data
-  bst <- lgb.train(
-    data = dtrain
-    , nrounds = nrounds
-    , num_leaves = 5L
-    , valids = list(
-      "train" = dtrain
-    )
-    , params = train_params
-  )
-  expect_identical(bst$best_iter, -1L)
-  expect_identical(bst$best_score, NA_real_)
-})
-
-test_that("lightgbm.train() gives the correct best_score and best_iter for a metric where higher values are better", {
-  set.seed(708L)
-  trainDF <- data.frame(
-    "feat1" = runif(n = 500L, min = 0.0, max = 15.0)
-    , "target" = rep(c(0L, 1L), 500L)
-  )
-  validDF <- data.frame(
-    "feat1" = runif(n = 50L, min = 0.0, max = 15.0)
-    , "target" = rep(c(0L, 1L), 50L)
-  )
-  dtrain <- lgb.Dataset(
-    data = as.matrix(trainDF[["feat1"]], drop = FALSE)
-    , label = trainDF[["target"]]
-  )
-  dvalid1 <- lgb.Dataset(
-    data = as.matrix(validDF[1L:25L, "feat1"], drop = FALSE)
-    , label = validDF[1L:25L, "target"]
-  )
-  nrounds <- 10L
-  bst <- lgb.train(
-    data = dtrain
-    , nrounds = nrounds
-    , num_leaves = 5L
-    , valids = list(
-      "valid1" = dvalid1
-      , "something-random-we-would-not-hardcode" = dtrain
-    )
-    , params = list(
-      objective = "binary"
-      , metric = "auc"
-      , learning_rate = 1.5
-    )
-  )
-  # note that "something-random-we-would-not-hardcode" was recognized as the training
-  # data even though it isn't named "train"
-  expect_named(
-    bst$record_evals
-    , c("start_iter", "something-random-we-would-not-hardcode", "valid1")
-    , ignore.order = FALSE
-    , ignore.case = FALSE
-  )
-  auc_scores <- unlist(bst$record_evals[["valid1"]][["auc"]][["eval"]])
-  expect_length(auc_scores, nrounds)
-  expect_identical(bst$best_iter, which.max(auc_scores))
-  expect_identical(bst$best_score, auc_scores[which.max(auc_scores)])
-})
-
-test_that("using lightgbm() without early stopping, best_iter and best_score come from valids and not training data", {
-  set.seed(708L)
-  # example: train second (called "something-random-we-would-not-hardcode"), two valids,
-  #          and a metric where higher values are better ("auc")
-  trainDF <- data.frame(
-    "feat1" = runif(n = 500L, min = 0.0, max = 15.0)
-    , "target" = rep(c(0L, 1L), 500L)
-  )
-  validDF <- data.frame(
-    "feat1" = runif(n = 50L, min = 0.0, max = 15.0)
-    , "target" = rep(c(0L, 1L), 50L)
-  )
-  dtrain <- lgb.Dataset(
-    data = as.matrix(trainDF[["feat1"]], drop = FALSE)
-    , label = trainDF[["target"]]
-  )
-  dvalid1 <- lgb.Dataset(
-    data = as.matrix(validDF[1L:25L, "feat1"], drop = FALSE)
-    , label = validDF[1L:25L, "target"]
-  )
-  dvalid2 <- lgb.Dataset(
-    data = as.matrix(validDF[26L:50L, "feat1"], drop = FALSE)
-    , label = validDF[26L:50L, "target"]
-  )
-  nrounds <- 10L
-  bst <- lightgbm(
-    data = dtrain
-    , nrounds = nrounds
-    , num_leaves = 5L
-    , valids = list(
-      "valid1" = dvalid1
-      , "something-random-we-would-not-hardcode" = dtrain
-      , "valid2" = dvalid2
-    )
-    , params = list(
-      objective = "binary"
-      , metric = "auc"
-      , learning_rate = 1.5
-    )
-    , verbose = -7L
-    , save_name = tempfile(fileext = ".model")
-  )
-  # when verbose <= 0 is passed to lightgbm(), 'valids' is passed through to lgb.train()
-  # untouched. If you set verbose to > 0, the training data will still be first but called "train"
-  expect_named(
-    bst$record_evals
-    , c("start_iter", "something-random-we-would-not-hardcode", "valid1", "valid2")
-    , ignore.order = FALSE
-    , ignore.case = FALSE
-  )
-  auc_scores <- unlist(bst$record_evals[["valid1"]][["auc"]][["eval"]])
-  expect_length(auc_scores, nrounds)
-  expect_identical(bst$best_iter, which.max(auc_scores))
-  expect_identical(bst$best_score, auc_scores[which.max(auc_scores)])
-})
-
-test_that("lgb.cv() works when you specify both 'metric' and 'eval' with strings", {
-  set.seed(708L)
-  nrounds <- 10L
-  nfolds <- 4L
-  increasing_metric_starting_value <- get(ACCUMULATOR_NAME, envir = .GlobalEnv)
-  bst <- lgb.cv(
-    params = list(
-      objective = "binary"
-      , metric = "binary_error"
-    )
-    , data = DTRAIN_RANDOM_CLASSIFICATION
-    , nrounds = nrounds
-    , nfold = nfolds
-    , eval = "binary_logloss"
-  )
-
-  # both metrics should have been used
-  expect_named(
-    bst$record_evals[["valid"]]
-    , expected = c("binary_error", "binary_logloss")
-    , ignore.order = TRUE
-    , ignore.case = FALSE
-  )
-
-  # the difference metrics shouldn't have been mixed up with each other
-  results <- bst$record_evals[["valid"]]
-  expect_true(abs(results[["binary_error"]][["eval"]][[1L]] - 0.5005654) < TOLERANCE)
-  expect_true(abs(results[["binary_logloss"]][["eval"]][[1L]] - 0.7011232) < TOLERANCE)
-
-  # all boosters should have been created
-  expect_length(bst$boosters, nfolds)
-})
-
-test_that("lgb.cv() works when you give a function for eval", {
-  set.seed(708L)
-  nrounds <- 10L
-  nfolds <- 3L
-  increasing_metric_starting_value <- get(ACCUMULATOR_NAME, envir = .GlobalEnv)
-  bst <- lgb.cv(
-    params = list(
-      objective = "binary"
-      , metric = "None"
-    )
-    , data = DTRAIN_RANDOM_CLASSIFICATION
-    , nfold = nfolds
-    , nrounds = nrounds
-    , eval = .constant_metric
-  )
-
-  # the difference metrics shouldn't have been mixed up with each other
-  results <- bst$record_evals[["valid"]]
-  expect_true(abs(results[["constant_metric"]][["eval"]][[1L]] - CONSTANT_METRIC_VALUE) < TOLERANCE)
-  expect_named(results, "constant_metric")
-})
-
-test_that("If first_metric_only is TRUE, lgb.cv() decides to stop early based on only the first metric", {
-  set.seed(708L)
-  nrounds <- 10L
-  nfolds <- 5L
-  early_stopping_rounds <- 3L
-  increasing_metric_starting_value <- get(ACCUMULATOR_NAME, envir = .GlobalEnv)
-  bst <- lgb.cv(
-    params = list(
-      objective = "regression"
-      , metric = "None"
-      , early_stopping_rounds = early_stopping_rounds
-      , first_metric_only = TRUE
-    )
-    , data = DTRAIN_RANDOM_REGRESSION
-    , nfold = nfolds
-    , nrounds = nrounds
-    , eval = list(
-      .increasing_metric
-      , .constant_metric
-    )
-  )
-
-  # Only the two functions provided to "eval" should have been evaluated
-  expect_named(bst$record_evals[["valid"]], c("increasing_metric", "constant_metric"))
-
-  # all 10 iterations should happen, and the best_iter should be the final one
-  expect_equal(bst$best_iter, nrounds)
-
-  # best_score should be taken from "increasing_metric"
-  #
-  # this expected value looks magical and confusing, but it's because
-  # evaluation metrics are averaged over all folds.
-  #
-  # consider 5-fold CV with a metric that adds 0.1 to a global accumulator
-  # each time it's called
-  #
-  # * iter 1: [0.1, 0.2, 0.3, 0.4, 0.5] (mean = 0.3)
-  # * iter 2: [0.6, 0.7, 0.8, 0.9, 1.0] (mean = 1.3)
-  # * iter 3: [1.1, 1.2, 1.3, 1.4, 1.5] (mean = 1.8)
-  #
-  cv_value <- increasing_metric_starting_value + mean(seq_len(nfolds) / 10.0) + (nrounds  - 1L) * 0.1 * nfolds
-  expect_equal(bst$best_score, cv_value)
-
-  # early stopping should not have happened. Even though constant_metric
-  # had 9 consecutive iterations with no improvement, it is ignored because of
-  # first_metric_only = TRUE
-  expect_equal(
-    length(bst$record_evals[["valid"]][["constant_metric"]][["eval"]])
-    , nrounds
-  )
-  expect_equal(
-    length(bst$record_evals[["valid"]][["increasing_metric"]][["eval"]])
-    , nrounds
-  )
-})
-
-test_that("early stopping works with lgb.cv()", {
-  set.seed(708L)
-  nrounds <- 10L
-  nfolds <- 5L
-  early_stopping_rounds <- 3L
-  increasing_metric_starting_value <- get(ACCUMULATOR_NAME, envir = .GlobalEnv)
-  bst <- lgb.cv(
-    params = list(
-      objective = "regression"
-      , metric = "None"
-      , early_stopping_rounds = early_stopping_rounds
-      , first_metric_only = TRUE
-    )
-    , data = DTRAIN_RANDOM_REGRESSION
-    , nfold = nfolds
-    , nrounds = nrounds
-    , eval = list(
-      .constant_metric
-      , .increasing_metric
-    )
-  )
-
-  # only the two functions provided to "eval" should have been evaluated
-  expect_named(bst$record_evals[["valid"]], c("constant_metric", "increasing_metric"))
-
-  # best_iter should be based on the first metric. Since constant_metric
-  # never changes, its first iteration was the best oone
-  expect_equal(bst$best_iter, 1L)
-
-  # best_score should be taken from the first metri
-  expect_equal(bst$best_score, 0.2)
-
-  # early stopping should have happened, since constant_metric was the first
-  # one passed to eval and it will not improve over consecutive iterations
-  #
-  # note that this test is identical to the previous one, but with the
-  # order of the eval metrics switched
-  expect_equal(
-    length(bst$record_evals[["valid"]][["constant_metric"]][["eval"]])
-    , early_stopping_rounds + 1L
-  )
-  expect_equal(
-    length(bst$record_evals[["valid"]][["increasing_metric"]][["eval"]])
-    , early_stopping_rounds + 1L
-  )
-})
-
-context("linear learner")
-
-test_that("lgb.train() fit on linearly-relatead data improves when using linear learners", {
-  set.seed(708L)
-  .new_dataset <- function() {
-    X <- matrix(rnorm(100L), ncol = 1L)
-    return(lgb.Dataset(
-      data = X
-      , label = 2L * X + runif(nrow(X), 0L, 0.1)
-    ))
-  }
-
-  params <- list(
-    objective = "regression"
-    , verbose = -1L
-    , metric = "mse"
-    , seed = 0L
-    , num_leaves = 2L
-  )
-
-  dtrain <- .new_dataset()
-  bst <- lgb.train(
-    data = dtrain
-    , nrounds = 10L
-    , params = params
-    , valids = list("train" = dtrain)
-  )
-  expect_true(lgb.is.Booster(bst))
-
-  dtrain <- .new_dataset()
-  bst_linear <- lgb.train(
-    data = dtrain
-    , nrounds = 10L
-    , params = modifyList(params, list(linear_tree = TRUE))
-    , valids = list("train" = dtrain)
-  )
-  expect_true(lgb.is.Booster(bst_linear))
-
-  bst_last_mse <- bst$record_evals[["train"]][["l2"]][["eval"]][[10L]]
-  bst_lin_last_mse <- bst_linear$record_evals[["train"]][["l2"]][["eval"]][[10L]]
-  expect_true(bst_lin_last_mse <  bst_last_mse)
-})
-
-
-test_that("lgb.train() w/ linear learner fails already-constructed dataset with linear=false", {
-  testthat::skip("Skipping this test because it causes issues for valgrind")
-  set.seed(708L)
-  params <- list(
-    objective = "regression"
-    , verbose = -1L
-    , metric = "mse"
-    , seed = 0L
-    , num_leaves = 2L
-  )
-
-  dtrain <- lgb.Dataset(
-    data = matrix(rnorm(100L), ncol = 1L)
-    , label = rnorm(100L)
-  )
-  dtrain$construct()
-  expect_error({
-    bst_linear <- lgb.train(
-      data = dtrain
-      , nrounds = 10L
-      , params = modifyList(params, list(linear_tree = TRUE))
-    )
-  }, regexp = "Cannot change linear_tree after constructed Dataset handle")
-})
-
-test_that("lgb.train() works with linear learners even if Dataset has missing values", {
-  set.seed(708L)
-  .new_dataset <- function() {
-    values <- rnorm(100L)
-    values[sample(seq_len(length(values)), size = 10L)] <- NA_real_
-    X <- matrix(
-      data = sample(values, size = 100L)
-      , ncol = 1L
-    )
-    return(lgb.Dataset(
-      data = X
-      , label = 2L * X + runif(nrow(X), 0L, 0.1)
-    ))
-  }
-
-  params <- list(
-    objective = "regression"
-    , verbose = -1L
-    , metric = "mse"
-    , seed = 0L
-    , num_leaves = 2L
-  )
-
-  dtrain <- .new_dataset()
-  bst <- lgb.train(
-    data = dtrain
-    , nrounds = 10L
-    , params = params
-    , valids = list("train" = dtrain)
-  )
-  expect_true(lgb.is.Booster(bst))
-
-  dtrain <- .new_dataset()
-  bst_linear <- lgb.train(
-    data = dtrain
-    , nrounds = 10L
-    , params = modifyList(params, list(linear_tree = TRUE))
-    , valids = list("train" = dtrain)
-  )
-  expect_true(lgb.is.Booster(bst_linear))
-
-  bst_last_mse <- bst$record_evals[["train"]][["l2"]][["eval"]][[10L]]
-  bst_lin_last_mse <- bst_linear$record_evals[["train"]][["l2"]][["eval"]][[10L]]
-  expect_true(bst_lin_last_mse <  bst_last_mse)
-})
-
-test_that("lgb.train() works with linear learners, bagging, and a Dataset that has missing values", {
-  set.seed(708L)
-  .new_dataset <- function() {
-    values <- rnorm(100L)
-    values[sample(seq_len(length(values)), size = 10L)] <- NA_real_
-    X <- matrix(
-      data = sample(values, size = 100L)
-      , ncol = 1L
-    )
-    return(lgb.Dataset(
-      data = X
-      , label = 2L * X + runif(nrow(X), 0L, 0.1)
-    ))
-  }
-
-  params <- list(
-    objective = "regression"
-    , verbose = -1L
-    , metric = "mse"
-    , seed = 0L
-    , num_leaves = 2L
-    , bagging_freq = 1L
-    , subsample = 0.8
-  )
-
-  dtrain <- .new_dataset()
-  bst <- lgb.train(
-    data = dtrain
-    , nrounds = 10L
-    , params = params
-    , valids = list("train" = dtrain)
-  )
-  expect_true(lgb.is.Booster(bst))
-
-  dtrain <- .new_dataset()
-  bst_linear <- lgb.train(
-    data = dtrain
-    , nrounds = 10L
-    , params = modifyList(params, list(linear_tree = TRUE))
-    , valids = list("train" = dtrain)
-  )
-  expect_true(lgb.is.Booster(bst_linear))
-
-  bst_last_mse <- bst$record_evals[["train"]][["l2"]][["eval"]][[10L]]
-  bst_lin_last_mse <- bst_linear$record_evals[["train"]][["l2"]][["eval"]][[10L]]
-  expect_true(bst_lin_last_mse <  bst_last_mse)
-})
-
-test_that("lgb.train() works with linear learners and data where a feature has only 1 non-NA value", {
-  set.seed(708L)
-  .new_dataset <- function() {
-    values <- c(rnorm(100L), rep(NA_real_, 100L))
-    values[118L] <- rnorm(1L)
-    X <- matrix(
-      data = values
-      , ncol = 2L
-    )
-    return(lgb.Dataset(
-      data = X
-      , label = 2L * X[, 1L] + runif(nrow(X), 0L, 0.1)
-      , feature_pre_filter = FALSE
-    ))
-  }
-
-  params <- list(
-    objective = "regression"
-    , verbose = -1L
-    , metric = "mse"
-    , seed = 0L
-    , num_leaves = 2L
-  )
-
-  dtrain <- .new_dataset()
-  bst_linear <- lgb.train(
-    data = dtrain
-    , nrounds = 10L
-    , params = modifyList(params, list(linear_tree = TRUE))
-  )
-  expect_true(lgb.is.Booster(bst_linear))
-})
-
-test_that("lgb.train() works with linear learners when Dataset has categorical features", {
-  set.seed(708L)
-  .new_dataset <- function() {
-    X <- matrix(numeric(200L), nrow = 100L, ncol = 2L)
-    X[, 1L] <- rnorm(100L)
-    X[, 2L] <- sample(seq_len(4L), size = 100L, replace = TRUE)
-    return(lgb.Dataset(
-      data = X
-      , label = 2L * X[, 1L] + runif(nrow(X), 0L, 0.1)
-    ))
-  }
-
-  params <- list(
-    objective = "regression"
-    , verbose = -1L
-    , metric = "mse"
-    , seed = 0L
-    , num_leaves = 2L
-    , categorical_feature = 1L
-  )
-
-  dtrain <- .new_dataset()
-  bst <- lgb.train(
-    data = dtrain
-    , nrounds = 10L
-    , params = params
-    , valids = list("train" = dtrain)
-  )
-  expect_true(lgb.is.Booster(bst))
-
-  dtrain <- .new_dataset()
-  bst_linear <- lgb.train(
-    data = dtrain
-    , nrounds = 10L
-    , params = modifyList(params, list(linear_tree = TRUE))
-    , valids = list("train" = dtrain)
-  )
-  expect_true(lgb.is.Booster(bst_linear))
-
-  bst_last_mse <- bst$record_evals[["train"]][["l2"]][["eval"]][[10L]]
-  bst_lin_last_mse <- bst_linear$record_evals[["train"]][["l2"]][["eval"]][[10L]]
-  expect_true(bst_lin_last_mse <  bst_last_mse)
-})
-
-context("interaction constraints")
-
-test_that("lgb.train() throws an informative error if interaction_constraints is not a list", {
-  dtrain <- lgb.Dataset(train$data, label = train$label)
-  params <- list(objective = "regression", interaction_constraints = "[1,2],[3]")
-    expect_error({
-      bst <- lightgbm(
-        data = dtrain
-        , params = params
-        , nrounds = 2L
-      )
-    }, "interaction_constraints must be a list")
-})
-
-test_that(paste0("lgb.train() throws an informative error if the members of interaction_constraints ",
-                 "are not character or numeric vectors"), {
-  dtrain <- lgb.Dataset(train$data, label = train$label)
-  params <- list(objective = "regression", interaction_constraints = list(list(1L, 2L), list(3L)))
-    expect_error({
-      bst <- lightgbm(
-        data = dtrain
-        , params = params
-        , nrounds = 2L
-      )
-    }, "every element in interaction_constraints must be a character vector or numeric vector")
-})
-
-test_that("lgb.train() throws an informative error if interaction_constraints contains a too large index", {
-  dtrain <- lgb.Dataset(train$data, label = train$label)
-  params <- list(objective = "regression",
-                 interaction_constraints = list(c(1L, length(colnames(train$data)) + 1L), 3L))
-    expect_error({
-      bst <- lightgbm(
-        data = dtrain
-        , params = params
-        , nrounds = 2L
-      )
-    }, "supplied a too large value in interaction_constraints")
-})
-
-test_that(paste0("lgb.train() gives same result when interaction_constraints is specified as a list of ",
-                 "character vectors, numeric vectors, or a combination"), {
-  set.seed(1L)
-  dtrain <- lgb.Dataset(train$data, label = train$label)
-
-  params <- list(objective = "regression", interaction_constraints = list(c(1L, 2L), 3L))
-  bst <- lightgbm(
-    data = dtrain
-    , params = params
-    , nrounds = 2L
-  )
-  pred1 <- bst$predict(test$data)
-
-  cnames <- colnames(train$data)
-  params <- list(objective = "regression", interaction_constraints = list(c(cnames[[1L]], cnames[[2L]]), cnames[[3L]]))
-  bst <- lightgbm(
-    data = dtrain
-    , params = params
-    , nrounds = 2L
-  )
-  pred2 <- bst$predict(test$data)
-
-  params <- list(objective = "regression", interaction_constraints = list(c(cnames[[1L]], cnames[[2L]]), 3L))
-  bst <- lightgbm(
-    data = dtrain
-    , params = params
-    , nrounds = 2L
-  )
-  pred3 <- bst$predict(test$data)
-
-  expect_equal(pred1, pred2)
-  expect_equal(pred2, pred3)
-
-})
-
-test_that(paste0("lgb.train() gives same results when using interaction_constraints and specifying colnames"), {
-  set.seed(1L)
-  dtrain <- lgb.Dataset(train$data, label = train$label)
-
-  params <- list(objective = "regression", interaction_constraints = list(c(1L, 2L), 3L))
-  bst <- lightgbm(
-    data = dtrain
-    , params = params
-    , nrounds = 2L
-  )
-  pred1 <- bst$predict(test$data)
-
-  new_colnames <- paste0(colnames(train$data), "_x")
-  params <- list(objective = "regression"
-                 , interaction_constraints = list(c(new_colnames[1L], new_colnames[2L]), new_colnames[3L]))
-  bst <- lightgbm(
-    data = dtrain
-    , params = params
-    , nrounds = 2L
-    , colnames = new_colnames
-  )
-  pred2 <- bst$predict(test$data)
-
-  expect_equal(pred1, pred2)
-
-})
diff --git a/R-package/tests/testthat/test_custom_objective.R b/R-package/tests/testthat/test_custom_objective.R
deleted file mode 100644
index f3224e9eb..000000000
--- a/R-package/tests/testthat/test_custom_objective.R
+++ /dev/null
@@ -1,69 +0,0 @@
-context("Test models with custom objective")
-
-data(agaricus.train, package = "lightgbm")
-data(agaricus.test, package = "lightgbm")
-dtrain <- lgb.Dataset(agaricus.train$data, label = agaricus.train$label)
-dtest <- lgb.Dataset(agaricus.test$data, label = agaricus.test$label)
-watchlist <- list(eval = dtest, train = dtrain)
-
-TOLERANCE <- 1e-6
-
-logregobj <- function(preds, dtrain) {
-  labels <- getinfo(dtrain, "label")
-  preds <- 1.0 / (1.0 + exp(-preds))
-  grad <- preds - labels
-  hess <- preds * (1.0 - preds)
-  return(list(grad = grad, hess = hess))
-}
-
-# User-defined evaluation function returns a pair (metric_name, result, higher_better)
-# NOTE: when you do customized loss function, the default prediction value is margin
-# This may make built-in evalution metric calculate wrong results
-# Keep this in mind when you use the customization, and maybe you need write customized evaluation function
-evalerror <- function(preds, dtrain) {
-  labels <- getinfo(dtrain, "label")
-  preds <- 1.0 / (1.0 + exp(-preds))
-  err <- as.numeric(sum(labels != (preds > 0.5))) / length(labels)
-  return(list(
-    name = "error"
-    , value = err
-    , higher_better = FALSE
-  ))
-}
-
-param <- list(
-  num_leaves = 8L
-  , learning_rate = 1.0
-  , objective = logregobj
-  , metric = "auc"
-)
-num_round <- 10L
-
-test_that("custom objective works", {
-  bst <- lgb.train(param, dtrain, num_round, watchlist, eval = evalerror)
-  expect_false(is.null(bst$record_evals))
-})
-
-test_that("using a custom objective, custom eval, and no other metrics works", {
-  set.seed(708L)
-  bst <- lgb.train(
-    params = list(
-      num_leaves = 8L
-      , learning_rate = 1.0
-    )
-    , data = dtrain
-    , nrounds = 4L
-    , valids = watchlist
-    , obj = logregobj
-    , eval = evalerror
-  )
-  expect_false(is.null(bst$record_evals))
-  expect_equal(bst$best_iter, 4L)
-  expect_true(abs(bst$best_score - 0.000621) < TOLERANCE)
-
-  eval_results <- bst$eval_valid(feval = evalerror)[[1L]]
-  expect_true(eval_results[["data_name"]] == "eval")
-  expect_true(abs(eval_results[["value"]] - 0.0006207325) < TOLERANCE)
-  expect_true(eval_results[["name"]] == "error")
-  expect_false(eval_results[["higher_better"]])
-})
diff --git a/R-package/tests/testthat/test_dataset.R b/R-package/tests/testthat/test_dataset.R
deleted file mode 100644
index 6d3fb188e..000000000
--- a/R-package/tests/testthat/test_dataset.R
+++ /dev/null
@@ -1,280 +0,0 @@
-library(lightgbm)
-library(Matrix)
-
-context("testing lgb.Dataset functionality")
-
-data(agaricus.test, package = "lightgbm")
-test_data <- agaricus.test$data[1L:100L, ]
-test_label <- agaricus.test$label[1L:100L]
-
-test_that("lgb.Dataset: basic construction, saving, loading", {
-  # from sparse matrix
-  dtest1 <- lgb.Dataset(test_data, label = test_label)
-  # from dense matrix
-  dtest2 <- lgb.Dataset(as.matrix(test_data), label = test_label)
-  expect_equal(getinfo(dtest1, "label"), getinfo(dtest2, "label"))
-
-  # save to a local file
-  tmp_file <- tempfile("lgb.Dataset_")
-  lgb.Dataset.save(dtest1, tmp_file)
-  # read from a local file
-  dtest3 <- lgb.Dataset(tmp_file)
-  lgb.Dataset.construct(dtest3)
-  unlink(tmp_file)
-  expect_equal(getinfo(dtest1, "label"), getinfo(dtest3, "label"))
-})
-
-test_that("lgb.Dataset: getinfo & setinfo", {
-  dtest <- lgb.Dataset(test_data)
-  dtest$construct()
-
-  setinfo(dtest, "label", test_label)
-  labels <- getinfo(dtest, "label")
-  expect_equal(test_label, getinfo(dtest, "label"))
-
-  expect_true(length(getinfo(dtest, "weight")) == 0L)
-  expect_true(length(getinfo(dtest, "init_score")) == 0L)
-
-  # any other label should error
-  expect_error(setinfo(dtest, "asdf", test_label))
-})
-
-test_that("lgb.Dataset: slice, dim", {
-  dtest <- lgb.Dataset(test_data, label = test_label)
-  lgb.Dataset.construct(dtest)
-  expect_equal(dim(dtest), dim(test_data))
-  dsub1 <- slice(dtest, seq_len(42L))
-  lgb.Dataset.construct(dsub1)
-  expect_equal(nrow(dsub1), 42L)
-  expect_equal(ncol(dsub1), ncol(test_data))
-})
-
-test_that("lgb.Dataset: colnames", {
-  dtest <- lgb.Dataset(test_data, label = test_label)
-  expect_equal(colnames(dtest), colnames(test_data))
-  lgb.Dataset.construct(dtest)
-  expect_equal(colnames(dtest), colnames(test_data))
-  expect_error({
-    colnames(dtest) <- "asdf"
-  })
-  new_names <- make.names(seq_len(ncol(test_data)))
-  expect_silent(colnames(dtest) <- new_names)
-  expect_equal(colnames(dtest), new_names)
-})
-
-test_that("lgb.Dataset: nrow is correct for a very sparse matrix", {
-  nr <- 1000L
-  x <- Matrix::rsparsematrix(nr, 100L, density = 0.0005)
-  # we want it very sparse, so that last rows are empty
-  expect_lt(max(x@i), nr)
-  dtest <- lgb.Dataset(x)
-  expect_equal(dim(dtest), dim(x))
-})
-
-test_that("lgb.Dataset: Dataset should be able to construct from matrix and return non-null handle", {
-  rawData <- matrix(runif(1000L), ncol = 10L)
-  handle <- lgb.null.handle()
-  ref_handle <- NULL
-  .Call(
-    LGBM_DatasetCreateFromMat_R
-    , rawData
-    , nrow(rawData)
-    , ncol(rawData)
-    , lightgbm:::lgb.params2str(params = list())
-    , ref_handle
-    , handle
-  )
-  expect_false(is.na(handle))
-  .Call(LGBM_DatasetFree_R, handle)
-  handle <- NULL
-})
-
-test_that("cpp errors should be raised as proper R errors", {
-  data(agaricus.train, package = "lightgbm")
-  train <- agaricus.train
-  dtrain <- lgb.Dataset(
-    train$data
-    , label = train$label
-    , init_score = seq_len(10L)
-  )
-  expect_error({
-    dtrain$construct()
-  }, regexp = "Initial score size doesn't match data size")
-})
-
-test_that("lgb.Dataset$setinfo() should convert 'group' to integer", {
-  ds <- lgb.Dataset(
-    data = matrix(rnorm(100L), nrow = 50L, ncol = 2L)
-    , label = sample(c(0L, 1L), size = 50L, replace = TRUE)
-  )
-  ds$construct()
-  current_group <- ds$getinfo("group")
-  expect_null(current_group)
-  group_as_numeric <- rep(25.0, 2L)
-  ds$setinfo("group", group_as_numeric)
-  expect_identical(ds$getinfo("group"), as.integer(group_as_numeric))
-})
-
-test_that("lgb.Dataset should throw an error if 'reference' is provided but of the wrong format", {
-  data(agaricus.test, package = "lightgbm")
-  test_data <- agaricus.test$data[1L:100L, ]
-  test_label <- agaricus.test$label[1L:100L]
-  # Try to trick lgb.Dataset() into accepting bad input
-  expect_error({
-    dtest <- lgb.Dataset(
-      data = test_data
-      , label = test_label
-      , reference = data.frame(x = seq_len(10L), y = seq_len(10L))
-    )
-  }, regexp = "reference must be a")
-})
-
-test_that("Dataset$new() should throw an error if 'predictor' is provided but of the wrong format", {
-  data(agaricus.test, package = "lightgbm")
-  test_data <- agaricus.test$data[1L:100L, ]
-  test_label <- agaricus.test$label[1L:100L]
-  expect_error({
-    dtest <- Dataset$new(
-      data = test_data
-      , label = test_label
-      , predictor = data.frame(x = seq_len(10L), y = seq_len(10L))
-    )
-  }, regexp = "predictor must be a", fixed = TRUE)
-})
-
-test_that("Dataset$get_params() successfully returns parameters if you passed them", {
-  # note that this list uses one "main" parameter (feature_pre_filter) and one that
-  # is an alias (is_sparse), to check that aliases are handled correctly
-  params <- list(
-    "feature_pre_filter" = TRUE
-    , "is_sparse" = FALSE
-  )
-  ds <- lgb.Dataset(
-    test_data
-    , label = test_label
-    , params = params
-  )
-  returned_params <- ds$get_params()
-  expect_identical(class(returned_params), "list")
-  expect_identical(length(params), length(returned_params))
-  expect_identical(sort(names(params)), sort(names(returned_params)))
-  for (param_name in names(params)) {
-    expect_identical(params[[param_name]], returned_params[[param_name]])
-  }
-})
-
-test_that("Dataset$get_params() ignores irrelevant parameters", {
-  params <- list(
-    "feature_pre_filter" = TRUE
-    , "is_sparse" = FALSE
-    , "nonsense_parameter" = c(1.0, 2.0, 5.0)
-  )
-  ds <- lgb.Dataset(
-    test_data
-    , label = test_label
-    , params = params
-  )
-  returned_params <- ds$get_params()
-  expect_false("nonsense_parameter" %in% names(returned_params))
-})
-
-test_that("Dataset$update_parameters() does nothing for empty inputs", {
-  ds <- lgb.Dataset(
-    test_data
-    , label = test_label
-  )
-  initial_params <- ds$get_params()
-  expect_identical(initial_params, list())
-
-  # update_params() should return "self" so it can be chained
-  res <- ds$update_params(
-    params = list()
-  )
-  expect_true(lgb.is.Dataset(res))
-
-  new_params <- ds$get_params()
-  expect_identical(new_params, initial_params)
-})
-
-test_that("Dataset$update_params() works correctly for recognized Dataset parameters", {
-  ds <- lgb.Dataset(
-    test_data
-    , label = test_label
-  )
-  initial_params <- ds$get_params()
-  expect_identical(initial_params, list())
-
-  new_params <- list(
-    "data_random_seed" = 708L
-    , "enable_bundle" = FALSE
-  )
-  res <- ds$update_params(
-    params = new_params
-  )
-  expect_true(lgb.is.Dataset(res))
-
-  updated_params <- ds$get_params()
-  for (param_name in names(new_params)) {
-    expect_identical(new_params[[param_name]], updated_params[[param_name]])
-  }
-})
-
-test_that("lgb.Dataset: should be able to run lgb.train() immediately after using lgb.Dataset() on a file", {
-  dtest <- lgb.Dataset(
-    data = test_data
-    , label = test_label
-  )
-  tmp_file <- tempfile(pattern = "lgb.Dataset_")
-  lgb.Dataset.save(
-    dataset = dtest
-    , fname = tmp_file
-  )
-
-  # read from a local file
-  dtest_read_in <- lgb.Dataset(data = tmp_file)
-
-  param <- list(
-    objective = "binary"
-    , metric = "binary_logloss"
-    , num_leaves = 5L
-    , learning_rate = 1.0
-  )
-
-  # should be able to train right away
-  bst <- lgb.train(
-    params = param
-    , data = dtest_read_in
-  )
-
-  expect_true(lgb.is.Booster(x = bst))
-})
-
-test_that("lgb.Dataset: should be able to run lgb.cv() immediately after using lgb.Dataset() on a file", {
-  dtest <- lgb.Dataset(
-    data = test_data
-    , label = test_label
-  )
-  tmp_file <- tempfile(pattern = "lgb.Dataset_")
-  lgb.Dataset.save(
-    dataset = dtest
-    , fname = tmp_file
-  )
-
-  # read from a local file
-  dtest_read_in <- lgb.Dataset(data = tmp_file)
-
-  param <- list(
-    objective = "binary"
-    , metric = "binary_logloss"
-    , num_leaves = 5L
-    , learning_rate = 1.0
-  )
-
-  # should be able to train right away
-  bst <- lgb.cv(
-    params = param
-    , data = dtest_read_in
-  )
-
-  expect_is(bst, "lgb.CVBooster")
-})
diff --git a/R-package/tests/testthat/test_learning_to_rank.R b/R-package/tests/testthat/test_learning_to_rank.R
deleted file mode 100644
index d4f573710..000000000
--- a/R-package/tests/testthat/test_learning_to_rank.R
+++ /dev/null
@@ -1,150 +0,0 @@
-context("Learning to rank")
-
-# numerical tolerance to use when checking metric values
-TOLERANCE <- 1e-06
-
-ON_SOLARIS <- Sys.info()["sysname"] == "SunOS"
-ON_32_BIT_WINDOWS <- .Platform$OS.type == "windows" && .Machine$sizeof.pointer != 8L
-
-test_that("learning-to-rank with lgb.train() works as expected", {
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    # just keep a few features,to generate an model with imperfect fit
-    train <- agaricus.train
-    train_data <- train$data[1L:6000L, 1L:20L]
-    dtrain <- lgb.Dataset(
-        train_data
-        , label = train$label[1L:6000L]
-        , group = rep(150L, 40L)
-    )
-    ndcg_at <- "1,2,3"
-    eval_names <-  paste0("ndcg@", strsplit(ndcg_at, ",")[[1L]])
-    params <- list(
-        objective = "lambdarank"
-        , metric = "ndcg"
-        , ndcg_at = ndcg_at
-        , lambdarank_truncation_level = 3L
-        , learning_rate = 0.001
-    )
-    model <- lgb.train(
-        params = params
-        , data = dtrain
-        , nrounds = 10L
-    )
-    expect_true(lgb.is.Booster(model))
-
-    dumped_model <- jsonlite::fromJSON(
-        model$dump_model()
-    )
-    expect_equal(dumped_model[["objective"]], "lambdarank")
-    expect_equal(dumped_model[["max_feature_idx"]], ncol(train_data) - 1L)
-
-    # check that evaluation results make sense (0.0 < nDCG < 1.0)
-    eval_results <- model$eval_train()
-    expect_equal(length(eval_results), length(eval_names))
-    for (result in eval_results) {
-        expect_true(result[["value"]] > 0.0 && result[["value"]] < 1.0)
-        expect_true(result[["higher_better"]])
-        expect_identical(result[["data_name"]], "training")
-    }
-    expect_identical(sapply(eval_results, function(x) {x$name}), eval_names)
-    expect_equal(eval_results[[1L]][["value"]], 0.775)
-    if (!(ON_SOLARIS || ON_32_BIT_WINDOWS)) {
-        expect_true(abs(eval_results[[2L]][["value"]] - 0.745986) < TOLERANCE)
-        expect_true(abs(eval_results[[3L]][["value"]] - 0.7351959) < TOLERANCE)
-    }
-})
-
-test_that("learning-to-rank with lgb.cv() works as expected", {
-    testthat::skip_if(
-        ON_SOLARIS || ON_32_BIT_WINDOWS
-        , message = "Skipping on Solaris and 32-bit Windows"
-    )
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    # just keep a few features,to generate an model with imperfect fit
-    train <- agaricus.train
-    train_data <- train$data[1L:6000L, 1L:20L]
-    dtrain <- lgb.Dataset(
-        train_data
-        , label = train$label[1L:6000L]
-        , group = rep(150L, 40L)
-    )
-    ndcg_at <- "1,2,3"
-    eval_names <-  paste0("ndcg@", strsplit(ndcg_at, ",")[[1L]])
-    params <- list(
-        objective = "lambdarank"
-        , metric = "ndcg"
-        , ndcg_at = ndcg_at
-        , lambdarank_truncation_level = 3L
-        , label_gain = "0,1,3"
-    )
-    nfold <- 4L
-    nrounds <- 10L
-    cv_bst <- lgb.cv(
-        params = params
-        , data = dtrain
-        , nrounds = nrounds
-        , nfold = nfold
-        , min_data = 1L
-        , learning_rate = 0.01
-    )
-    expect_is(cv_bst, "lgb.CVBooster")
-    expect_equal(length(cv_bst$boosters), nfold)
-
-    # "valid" should contain results for each metric
-    eval_results <- cv_bst$record_evals[["valid"]]
-    eval_names <-  c("ndcg@1", "ndcg@2", "ndcg@3")
-    expect_identical(names(eval_results), eval_names)
-
-    # check that best score and iter make sense (0.0 < nDCG < 1.0)
-    best_iter <- cv_bst$best_iter
-    best_score <- cv_bst$best_score
-    expect_true(best_iter > 0L && best_iter <= nrounds)
-    expect_true(best_score > 0.0 && best_score < 1.0)
-    expect_true(abs(best_score - 0.75) < TOLERANCE)
-
-    # best_score should be set for the first metric
-    first_metric <- eval_names[[1L]]
-    expect_equal(best_score, eval_results[[first_metric]][["eval"]][[best_iter]])
-
-    for (eval_name in eval_names) {
-        results_for_this_metric <- eval_results[[eval_name]]
-
-        # each set of metrics should have eval and eval_err
-        expect_identical(names(results_for_this_metric), c("eval", "eval_err"))
-
-        # there should be one "eval" and "eval_err" per round
-        expect_equal(length(results_for_this_metric[["eval"]]), nrounds)
-        expect_equal(length(results_for_this_metric[["eval_err"]]), nrounds)
-
-        # check that evaluation results make sense (0.0 < nDCG < 1.0)
-        all_evals <- unlist(results_for_this_metric[["eval"]])
-        expect_true(all(all_evals > 0.0 & all_evals < 1.0))
-    }
-
-    # first and last value of each metric should be as expected
-    ndcg1_values <- c(0.675, 0.725, 0.65, 0.725, 0.75, 0.725, 0.75, 0.725, 0.75, 0.75)
-    expect_true(all(abs(unlist(eval_results[["ndcg@1"]][["eval"]]) - ndcg1_values) < TOLERANCE))
-
-    ndcg2_values <- c(
-        0.6556574, 0.6669721, 0.6306574, 0.6476294, 0.6629581,
-        0.6476294, 0.6629581, 0.6379581, 0.7113147, 0.6823008
-    )
-    expect_true(all(abs(unlist(eval_results[["ndcg@2"]][["eval"]]) - ndcg2_values) < TOLERANCE))
-
-    ndcg3_values <- c(
-        0.6484639, 0.6571238, 0.6469279, 0.6540516, 0.6481857,
-        0.6481857, 0.6481857, 0.6466496, 0.7027939, 0.6629898
-    )
-    expect_true(all(abs(unlist(eval_results[["ndcg@3"]][["eval"]]) - ndcg3_values) < TOLERANCE))
-
-    # check details of each booster
-    for (bst in cv_bst$boosters) {
-        dumped_model <- jsonlite::fromJSON(
-            bst$booster$dump_model()
-        )
-        expect_equal(dumped_model[["objective"]], "lambdarank")
-        expect_equal(dumped_model[["max_feature_idx"]], ncol(train_data) - 1L)
-    }
-})
diff --git a/R-package/tests/testthat/test_lgb.Booster.R b/R-package/tests/testthat/test_lgb.Booster.R
deleted file mode 100644
index 2b9e78b9e..000000000
--- a/R-package/tests/testthat/test_lgb.Booster.R
+++ /dev/null
@@ -1,809 +0,0 @@
-context("lgb.get.eval.result")
-
-test_that("lgb.get.eval.result() should throw an informative error if booster is not an lgb.Booster", {
-    bad_inputs <- list(
-        matrix(1.0:10.0, 2L, 5L)
-        , TRUE
-        , c("a", "b")
-        , NA
-        , 10L
-        , lgb.Dataset(
-            data = matrix(1.0:10.0, 2L, 5L)
-            , params = list()
-        )
-    )
-    for (bad_input in bad_inputs) {
-        expect_error({
-            lgb.get.eval.result(
-                booster = bad_input
-                , data_name = "test"
-                , eval_name = "l2"
-            )
-        }, regexp = "Can only use", fixed = TRUE)
-    }
-})
-
-test_that("lgb.get.eval.result() should throw an informative error for incorrect data_name", {
-    data(agaricus.train, package = "lightgbm")
-    data(agaricus.test, package = "lightgbm")
-    dtrain <- lgb.Dataset(
-        agaricus.train$data
-        , label = agaricus.train$label
-    )
-    model <- lgb.train(
-        params = list(
-            objective = "regression"
-            , metric = "l2"
-        )
-        , data = dtrain
-        , nrounds = 5L
-        , valids = list(
-            "test" = lgb.Dataset.create.valid(
-                dtrain
-                , agaricus.test$data
-                , label = agaricus.test$label
-            )
-        )
-        , min_data = 1L
-        , learning_rate = 1.0
-    )
-    expect_error({
-        eval_results <- lgb.get.eval.result(
-            booster = model
-            , data_name = "testing"
-            , eval_name = "l2"
-        )
-    }, regexp = "Only the following datasets exist in record evals: [test]", fixed = TRUE)
-})
-
-test_that("lgb.get.eval.result() should throw an informative error for incorrect eval_name", {
-    data(agaricus.train, package = "lightgbm")
-    data(agaricus.test, package = "lightgbm")
-    dtrain <- lgb.Dataset(
-        agaricus.train$data
-        , label = agaricus.train$label
-    )
-    model <- lgb.train(
-        params = list(
-            objective = "regression"
-            , metric = "l2"
-        )
-        , data = dtrain
-        , nrounds = 5L
-        , valids = list(
-            "test" = lgb.Dataset.create.valid(
-                dtrain
-                , agaricus.test$data
-                , label = agaricus.test$label
-            )
-        )
-        , min_data = 1L
-        , learning_rate = 1.0
-    )
-    expect_error({
-        eval_results <- lgb.get.eval.result(
-            booster = model
-            , data_name = "test"
-            , eval_name = "l1"
-        )
-    }, regexp = "Only the following eval_names exist for dataset.*\\: \\[l2\\]", fixed = FALSE)
-})
-
-context("lgb.load()")
-
-test_that("lgb.load() gives the expected error messages given different incorrect inputs", {
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    data(agaricus.test, package = "lightgbm")
-    train <- agaricus.train
-    test <- agaricus.test
-    bst <- lightgbm(
-        data = as.matrix(train$data)
-        , label = train$label
-        , num_leaves = 4L
-        , learning_rate = 1.0
-        , nrounds = 2L
-        , objective = "binary"
-        , save_name = tempfile(fileext = ".model")
-    )
-
-    # you have to give model_str or filename
-    expect_error({
-        lgb.load()
-    }, regexp = "either filename or model_str must be given")
-    expect_error({
-        lgb.load(filename = NULL, model_str = NULL)
-    }, regexp = "either filename or model_str must be given")
-
-    # if given, filename should be a string that points to an existing file
-    model_file <- tempfile(fileext = ".model")
-    expect_error({
-        lgb.load(filename = list(model_file))
-    }, regexp = "filename should be character")
-    file_to_check <- paste0("a.model")
-    while (file.exists(file_to_check)) {
-        file_to_check <- paste0("a", file_to_check)
-    }
-    expect_error({
-        lgb.load(filename = file_to_check)
-    }, regexp = "passed to filename does not exist")
-
-    # if given, model_str should be a string
-    expect_error({
-        lgb.load(model_str = c(4.0, 5.0, 6.0))
-    }, regexp = "model_str should be character")
-
-})
-
-test_that("Loading a Booster from a text file works", {
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    data(agaricus.test, package = "lightgbm")
-    train <- agaricus.train
-    test <- agaricus.test
-    bst <- lightgbm(
-        data = as.matrix(train$data)
-        , label = train$label
-        , num_leaves = 4L
-        , learning_rate = 1.0
-        , nrounds = 2L
-        , objective = "binary"
-        , save_name = tempfile(fileext = ".model")
-    )
-    expect_true(lgb.is.Booster(bst))
-
-    pred <- predict(bst, test$data)
-    model_file <- tempfile(fileext = ".model")
-    lgb.save(bst, model_file)
-
-    # finalize the booster and destroy it so you know we aren't cheating
-    bst$finalize()
-    expect_null(bst$.__enclos_env__$private$handle)
-    rm(bst)
-
-    bst2 <- lgb.load(
-        filename = model_file
-    )
-    pred2 <- predict(bst2, test$data)
-    expect_identical(pred, pred2)
-})
-
-test_that("boosters with linear models at leaves can be written to text file and re-loaded successfully", {
-    X <- matrix(rnorm(100L), ncol = 1L)
-    labels <- 2L * X + runif(nrow(X), 0L, 0.1)
-    dtrain <- lgb.Dataset(
-        data = X
-        , label = labels
-    )
-
-    params <- list(
-        objective = "regression"
-        , verbose = -1L
-        , metric = "mse"
-        , seed = 0L
-        , num_leaves = 2L
-    )
-
-    bst <- lgb.train(
-        data = dtrain
-        , nrounds = 10L
-        , params = params
-    )
-    expect_true(lgb.is.Booster(bst))
-
-    # save predictions, then write the model to a file and destroy it in R
-    preds <- predict(bst, X)
-    model_file <- tempfile(fileext = ".model")
-    lgb.save(bst, model_file)
-    bst$finalize()
-    expect_null(bst$.__enclos_env__$private$handle)
-    rm(bst)
-
-    # load the booster and make predictions...should be the same
-    bst2 <- lgb.load(
-        filename = model_file
-    )
-    preds2 <- predict(bst2, X)
-    expect_identical(preds, preds2)
-})
-
-
-test_that("Loading a Booster from a string works", {
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    data(agaricus.test, package = "lightgbm")
-    train <- agaricus.train
-    test <- agaricus.test
-    bst <- lightgbm(
-        data = as.matrix(train$data)
-        , label = train$label
-        , num_leaves = 4L
-        , learning_rate = 1.0
-        , nrounds = 2L
-        , objective = "binary"
-        , save_name = tempfile(fileext = ".model")
-    )
-    expect_true(lgb.is.Booster(bst))
-
-    pred <- predict(bst, test$data)
-    model_string <- bst$save_model_to_string()
-
-    # finalize the booster and destroy it so you know we aren't cheating
-    bst$finalize()
-    expect_null(bst$.__enclos_env__$private$handle)
-    rm(bst)
-
-    bst2 <- lgb.load(
-        model_str = model_string
-    )
-    pred2 <- predict(bst2, test$data)
-    expect_identical(pred, pred2)
-})
-
-test_that("If a string and a file are both passed to lgb.load() the file is used model_str is totally ignored", {
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    data(agaricus.test, package = "lightgbm")
-    train <- agaricus.train
-    test <- agaricus.test
-    bst <- lightgbm(
-        data = as.matrix(train$data)
-        , label = train$label
-        , num_leaves = 4L
-        , learning_rate = 1.0
-        , nrounds = 2L
-        , objective = "binary"
-        , save_name = tempfile(fileext = ".model")
-    )
-    expect_true(lgb.is.Booster(bst))
-
-    pred <- predict(bst, test$data)
-    model_file <- tempfile(fileext = ".model")
-    lgb.save(bst, model_file)
-
-    # finalize the booster and destroy it so you know we aren't cheating
-    bst$finalize()
-    expect_null(bst$.__enclos_env__$private$handle)
-    rm(bst)
-
-    bst2 <- lgb.load(
-        filename = model_file
-        , model_str = 4.0
-    )
-    pred2 <- predict(bst2, test$data)
-    expect_identical(pred, pred2)
-})
-
-context("Booster")
-
-test_that("Creating a Booster from a Dataset should work", {
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    data(agaricus.test, package = "lightgbm")
-    dtrain <- lgb.Dataset(
-        agaricus.train$data
-        , label = agaricus.train$label
-    )
-    bst <- Booster$new(
-        params = list(
-            objective = "binary"
-        ),
-        train_set = dtrain
-    )
-    expect_true(lgb.is.Booster(bst))
-    expect_equal(bst$current_iter(), 0L)
-    expect_true(is.na(bst$best_score))
-    expect_true(all(bst$predict(agaricus.train$data) == 0.5))
-})
-
-test_that("Creating a Booster from a Dataset with an existing predictor should work", {
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    nrounds <- 2L
-    bst <- lightgbm(
-        data = as.matrix(agaricus.train$data)
-        , label = agaricus.train$label
-        , num_leaves = 4L
-        , learning_rate = 1.0
-        , nrounds = nrounds
-        , objective = "binary"
-        , save_name = tempfile(fileext = ".model")
-    )
-    data(agaricus.test, package = "lightgbm")
-    dtest <- Dataset$new(
-        data = agaricus.test$data
-        , label = agaricus.test$label
-        , predictor = bst$to_predictor()
-    )
-    bst_from_ds <- Booster$new(
-        train_set = dtest
-    )
-    expect_true(lgb.is.Booster(bst))
-    expect_equal(bst$current_iter(), nrounds)
-    expect_equal(bst$eval_train()[[1L]][["value"]], 0.1115352)
-    expect_equal(bst_from_ds$current_iter(), nrounds)
-    dumped_model <- jsonlite::fromJSON(bst$dump_model())
-    expect_identical(bst_from_ds$eval_train(), list())
-    expect_equal(bst_from_ds$current_iter(), nrounds)
-})
-
-test_that("Booster$rollback_one_iter() should work as expected", {
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    data(agaricus.test, package = "lightgbm")
-    train <- agaricus.train
-    test <- agaricus.test
-    nrounds <- 5L
-    bst <- lightgbm(
-        data = as.matrix(train$data)
-        , label = train$label
-        , num_leaves = 4L
-        , learning_rate = 1.0
-        , nrounds = nrounds
-        , objective = "binary"
-        , save_name = tempfile(fileext = ".model")
-    )
-    expect_equal(bst$current_iter(), nrounds)
-    expect_true(lgb.is.Booster(bst))
-    logloss <- bst$eval_train()[[1L]][["value"]]
-    expect_equal(logloss, 0.01904786)
-
-    x <- bst$rollback_one_iter()
-
-    # rollback_one_iter() should return a booster and modify the original
-    # booster in place
-    expect_true(lgb.is.Booster(x))
-    expect_equal(bst$current_iter(), nrounds - 1L)
-
-    # score should now come from the model as of 4 iterations
-    logloss <- bst$eval_train()[[1L]][["value"]]
-    expect_equal(logloss, 0.027915146)
-})
-
-test_that("Booster$update() passing a train_set works as expected", {
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    nrounds <- 2L
-
-    # train with 2 rounds and then update
-    bst <- lightgbm(
-        data = as.matrix(agaricus.train$data)
-        , label = agaricus.train$label
-        , num_leaves = 4L
-        , learning_rate = 1.0
-        , nrounds = nrounds
-        , objective = "binary"
-        , save_name = tempfile(fileext = ".model")
-    )
-    expect_true(lgb.is.Booster(bst))
-    expect_equal(bst$current_iter(), nrounds)
-    bst$update(
-        train_set = Dataset$new(
-            data = agaricus.train$data
-            , label = agaricus.train$label
-        )
-    )
-    expect_true(lgb.is.Booster(bst))
-    expect_equal(bst$current_iter(), nrounds + 1L)
-
-    # train with 3 rounds directly
-    bst2 <- lightgbm(
-        data = as.matrix(agaricus.train$data)
-        , label = agaricus.train$label
-        , num_leaves = 4L
-        , learning_rate = 1.0
-        , nrounds = nrounds +  1L
-        , objective = "binary"
-        , save_name = tempfile(fileext = ".model")
-    )
-    expect_true(lgb.is.Booster(bst2))
-    expect_equal(bst2$current_iter(), nrounds +  1L)
-
-    # model with 2 rounds + 1 update should be identical to 3 rounds
-    expect_equal(bst2$eval_train()[[1L]][["value"]], 0.04806585)
-    expect_equal(bst$eval_train()[[1L]][["value"]], bst2$eval_train()[[1L]][["value"]])
-})
-
-test_that("Booster$update() throws an informative error if you provide a non-Dataset to update()", {
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    nrounds <- 2L
-
-    # train with 2 rounds and then update
-    bst <- lightgbm(
-        data = as.matrix(agaricus.train$data)
-        , label = agaricus.train$label
-        , num_leaves = 4L
-        , learning_rate = 1.0
-        , nrounds = nrounds
-        , objective = "binary"
-        , save_name = tempfile(fileext = ".model")
-    )
-    expect_error({
-        bst$update(
-            train_set = data.frame(x = rnorm(10L))
-        )
-    }, regexp = "lgb.Booster.update: Only can use lgb.Dataset", fixed = TRUE)
-})
-
-test_that("Booster should store parameters and Booster$reset_parameter() should update them", {
-    data(agaricus.train, package = "lightgbm")
-    dtrain <- lgb.Dataset(
-        agaricus.train$data
-        , label = agaricus.train$label
-    )
-    # testing that this works for some cases that could break it:
-    #    - multiple metrics
-    #    - using "metric", "boosting", "num_class" in params
-    params <- list(
-        objective = "multiclass"
-        , max_depth = 4L
-        , bagging_fraction = 0.8
-        , metric = c("multi_logloss", "multi_error")
-        , boosting = "gbdt"
-        , num_class = 5L
-    )
-    bst <- Booster$new(
-        params = params
-        , train_set = dtrain
-    )
-    expect_identical(bst$params, params)
-
-    params[["bagging_fraction"]] <- 0.9
-    ret_bst <- bst$reset_parameter(params = params)
-    expect_identical(ret_bst$params, params)
-    expect_identical(bst$params, params)
-})
-
-test_that("Booster$params should include dataset params, before and after Booster$reset_parameter()", {
-    data(agaricus.train, package = "lightgbm")
-    dtrain <- lgb.Dataset(
-        agaricus.train$data
-        , label = agaricus.train$label
-        , params = list(
-            max_bin = 17L
-        )
-    )
-    params <- list(
-        objective = "binary"
-        , max_depth = 4L
-        , bagging_fraction = 0.8
-    )
-    bst <- Booster$new(
-        params = params
-        , train_set = dtrain
-    )
-    expect_identical(
-        bst$params
-        , list(
-            objective = "binary"
-            , max_depth = 4L
-            , bagging_fraction = 0.8
-            , max_bin = 17L
-        )
-    )
-
-    params[["bagging_fraction"]] <- 0.9
-    ret_bst <- bst$reset_parameter(params = params)
-    expected_params <- list(
-        objective = "binary"
-        , max_depth = 4L
-        , bagging_fraction = 0.9
-        , max_bin = 17L
-    )
-    expect_identical(ret_bst$params, expected_params)
-    expect_identical(bst$params, expected_params)
-})
-
-context("save_model")
-
-test_that("Saving a model with different feature importance types works", {
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    train <- agaricus.train
-    bst <- lightgbm(
-        data = as.matrix(train$data)
-        , label = train$label
-        , num_leaves = 4L
-        , learning_rate = 1.0
-        , nrounds = 2L
-        , objective = "binary"
-        , save_name = tempfile(fileext = ".model")
-    )
-    expect_true(lgb.is.Booster(bst))
-
-    .feat_importance_from_string <- function(model_string) {
-        file_lines <- strsplit(model_string, "\n")[[1L]]
-        start_indx <- which(grepl("^feature_importances\\:$", file_lines)) + 1L
-        blank_line_indices <- which(file_lines == "")
-        end_indx <- blank_line_indices[blank_line_indices > start_indx][1L] - 1L
-        importances <- file_lines[start_indx: end_indx]
-        return(importances)
-    }
-
-    GAIN_IMPORTANCE <- 1L
-    model_string <- bst$save_model_to_string(feature_importance_type = GAIN_IMPORTANCE)
-    expect_equal(
-        .feat_importance_from_string(model_string)
-        , c(
-            "odor=none=4010"
-            , "stalk-root=club=1163"
-            , "stalk-root=rooted=573"
-            , "stalk-surface-above-ring=silky=450"
-            , "spore-print-color=green=397"
-            , "gill-color=buff=281"
-        )
-    )
-
-    SPLIT_IMPORTANCE <- 0L
-    model_string <- bst$save_model_to_string(feature_importance_type = SPLIT_IMPORTANCE)
-    expect_equal(
-        .feat_importance_from_string(model_string)
-        , c(
-            "odor=none=1"
-            , "gill-color=buff=1"
-            , "stalk-root=club=1"
-            , "stalk-root=rooted=1"
-            , "stalk-surface-above-ring=silky=1"
-            , "spore-print-color=green=1"
-        )
-    )
-})
-
-test_that("Saving a model with unknown importance type fails", {
-    testthat::skip("Skipping this test because it causes issues for valgrind")
-    set.seed(708L)
-    data(agaricus.train, package = "lightgbm")
-    train <- agaricus.train
-    bst <- lightgbm(
-        data = as.matrix(train$data)
-        , label = train$label
-        , num_leaves = 4L
-        , learning_rate = 1.0
-        , nrounds = 2L
-        , objective = "binary"
-        , save_name = tempfile(fileext = ".model")
-    )
-    expect_true(lgb.is.Booster(bst))
-
-    UNSUPPORTED_IMPORTANCE <- 2L
-    expect_error({
-        model_string <- bst$save_model_to_string(feature_importance_type = UNSUPPORTED_IMPORTANCE)
-    }, "Unknown importance type")
-})
-
-
-.params_from_model_string <- function(model_str) {
-    file_lines <- strsplit(model_str, "\n")[[1L]]
-    start_indx <- which(grepl("^parameters\\:$", file_lines)) + 1L
-    blank_line_indices <- which(file_lines == "")
-    end_indx <- blank_line_indices[blank_line_indices > start_indx][1L] - 1L
-    params <- file_lines[start_indx: end_indx]
-    return(params)
-}
-
-test_that("all parameters are stored correctly with save_model_to_string()", {
-    dtrain <- lgb.Dataset(
-        data = matrix(rnorm(500L), nrow = 100L)
-        , label = rnorm(100L)
-    )
-    nrounds <- 4L
-    bst <- lgb.train(
-        params = list(
-            objective = "regression"
-            , metric = "l2"
-        )
-        , data = dtrain
-        , nrounds = nrounds
-        , verbose = 0L
-    )
-
-    model_str <- bst$save_model_to_string()
-    params_in_file <- .params_from_model_string(model_str = model_str)
-
-    # parameters should match what was passed from the R package
-    expect_equal(sum(grepl(pattern = "^\\[metric\\:", x = params_in_file)), 1L)
-    expect_equal(sum(params_in_file == "[metric: l2]"), 1L)
-
-    expect_equal(sum(grepl(pattern = "^\\[num_iterations\\:", x = params_in_file)), 1L)
-    expect_equal(sum(params_in_file == "[num_iterations: 4]"), 1L)
-
-    expect_equal(sum(grepl(pattern = "^\\[objective\\:", x = params_in_file)), 1L)
-    expect_equal(sum(params_in_file == "[objective: regression]"), 1L)
-
-    expect_equal(sum(grepl(pattern = "^\\[verbosity\\:", x = params_in_file)), 1L)
-    expect_equal(sum(params_in_file == "[verbosity: 0]"), 1L)
-
-    # early stopping should be off by default
-    expect_equal(sum(grepl(pattern = "^\\[early_stopping_round\\:", x = params_in_file)), 1L)
-    expect_equal(sum(params_in_file == "[early_stopping_round: 0]"), 1L)
-})
-
-test_that("early_stopping, num_iterations are stored correctly in model string even with aliases", {
-    dtrain <- lgb.Dataset(
-        data = matrix(rnorm(500L), nrow = 100L)
-        , label = rnorm(100L)
-    )
-    dvalid <- lgb.Dataset(
-        data = matrix(rnorm(500L), nrow = 100L)
-        , label = rnorm(100L)
-    )
-
-    # num_iterations values (all different)
-    num_iterations <- 4L
-    num_boost_round <- 2L
-    n_iter <- 3L
-    nrounds_kwarg <- 6L
-
-    # early_stopping_round values (all different)
-    early_stopping_round <- 2L
-    early_stopping_round_kwarg <- 3L
-    n_iter_no_change <- 4L
-
-    params <- list(
-        objective = "regression"
-        , metric = "l2"
-        , num_boost_round = num_boost_round
-        , num_iterations = num_iterations
-        , n_iter = n_iter
-        , early_stopping_round = early_stopping_round
-        , n_iter_no_change = n_iter_no_change
-    )
-
-    bst <- lgb.train(
-        params = params
-        , data = dtrain
-        , nrounds = nrounds_kwarg
-        , early_stopping_rounds = early_stopping_round_kwarg
-        , valids = list(
-            "random_valid" = dvalid
-        )
-        , verbose = 0L
-    )
-
-    model_str <- bst$save_model_to_string()
-    params_in_file <- .params_from_model_string(model_str = model_str)
-
-    # parameters should match what was passed from the R package, and the "main" (non-alias)
-    # params values in `params` should be preferred to keyword argumentts or aliases
-    expect_equal(sum(grepl(pattern = "^\\[num_iterations\\:", x = params_in_file)), 1L)
-    expect_equal(sum(params_in_file == sprintf("[num_iterations: %s]", num_iterations)), 1L)
-    expect_equal(sum(grepl(pattern = "^\\[early_stopping_round\\:", x = params_in_file)), 1L)
-    expect_equal(sum(params_in_file == sprintf("[early_stopping_round: %s]", early_stopping_round)), 1L)
-
-    # none of the aliases shouold have been written to the model file
-    expect_equal(sum(grepl(pattern = "^\\[num_boost_round\\:", x = params_in_file)), 0L)
-    expect_equal(sum(grepl(pattern = "^\\[n_iter\\:", x = params_in_file)), 0L)
-    expect_equal(sum(grepl(pattern = "^\\[n_iter_no_change\\:", x = params_in_file)), 0L)
-
-})
-
-# this is almost identical to the test above it, but for lgb.cv(). A lot of code
-# is duplicated between lgb.train() and lgb.cv(), and this will catch cases where
-# one is updated and the other isn't
-test_that("lgb.cv() correctly handles passing through params to the model file", {
-    dtrain <- lgb.Dataset(
-        data = matrix(rnorm(500L), nrow = 100L)
-        , label = rnorm(100L)
-    )
-
-    # num_iterations values (all different)
-    num_iterations <- 4L
-    num_boost_round <- 2L
-    n_iter <- 3L
-    nrounds_kwarg <- 6L
-
-    # early_stopping_round values (all different)
-    early_stopping_round <- 2L
-    early_stopping_round_kwarg <- 3L
-    n_iter_no_change <- 4L
-
-    params <- list(
-        objective = "regression"
-        , metric = "l2"
-        , num_boost_round = num_boost_round
-        , num_iterations = num_iterations
-        , n_iter = n_iter
-        , early_stopping_round = early_stopping_round
-        , n_iter_no_change = n_iter_no_change
-    )
-
-    cv_bst <- lgb.cv(
-        params = params
-        , data = dtrain
-        , nrounds = nrounds_kwarg
-        , early_stopping_rounds = early_stopping_round_kwarg
-        , nfold = 3L
-        , verbose = 0L
-    )
-
-    for (bst in cv_bst$boosters) {
-        model_str <- bst[["booster"]]$save_model_to_string()
-        params_in_file <- .params_from_model_string(model_str = model_str)
-
-        # parameters should match what was passed from the R package, and the "main" (non-alias)
-        # params values in `params` should be preferred to keyword argumentts or aliases
-        expect_equal(sum(grepl(pattern = "^\\[num_iterations\\:", x = params_in_file)), 1L)
-        expect_equal(sum(params_in_file == sprintf("[num_iterations: %s]", num_iterations)), 1L)
-        expect_equal(sum(grepl(pattern = "^\\[early_stopping_round\\:", x = params_in_file)), 1L)
-        expect_equal(sum(params_in_file == sprintf("[early_stopping_round: %s]", early_stopping_round)), 1L)
-
-        # none of the aliases shouold have been written to the model file
-        expect_equal(sum(grepl(pattern = "^\\[num_boost_round\\:", x = params_in_file)), 0L)
-        expect_equal(sum(grepl(pattern = "^\\[n_iter\\:", x = params_in_file)), 0L)
-        expect_equal(sum(grepl(pattern = "^\\[n_iter_no_change\\:", x = params_in_file)), 0L)
-    }
-
-})
-
-context("saveRDS.lgb.Booster() and readRDS.lgb.Booster()")
-
-test_that("params (including dataset params) should be stored in .rds file for Booster", {
-    data(agaricus.train, package = "lightgbm")
-    dtrain <- lgb.Dataset(
-        agaricus.train$data
-        , label = agaricus.train$label
-        , params = list(
-            max_bin = 17L
-        )
-    )
-    params <- list(
-        objective = "binary"
-        , max_depth = 4L
-        , bagging_fraction = 0.8
-    )
-    bst <- Booster$new(
-        params = params
-        , train_set = dtrain
-    )
-    bst_file <- tempfile(fileext = ".rds")
-    saveRDS.lgb.Booster(bst, file = bst_file)
-
-    bst_from_file <- readRDS.lgb.Booster(file = bst_file)
-    expect_identical(
-        bst_from_file$params
-        , list(
-            objective = "binary"
-            , max_depth = 4L
-            , bagging_fraction = 0.8
-            , max_bin = 17L
-        )
-    )
-})
-
-test_that("boosters with linear models at leaves can be written to RDS and re-loaded successfully", {
-    X <- matrix(rnorm(100L), ncol = 1L)
-    labels <- 2L * X + runif(nrow(X), 0L, 0.1)
-    dtrain <- lgb.Dataset(
-        data = X
-        , label = labels
-    )
-
-    params <- list(
-        objective = "regression"
-        , verbose = -1L
-        , metric = "mse"
-        , seed = 0L
-        , num_leaves = 2L
-    )
-
-    bst <- lgb.train(
-        data = dtrain
-        , nrounds = 10L
-        , params = params
-    )
-    expect_true(lgb.is.Booster(bst))
-
-    # save predictions, then write the model to a file and destroy it in R
-    preds <- predict(bst, X)
-    model_file <- tempfile(fileext = ".rds")
-    saveRDS.lgb.Booster(bst, file = model_file)
-    bst$finalize()
-    expect_null(bst$.__enclos_env__$private$handle)
-    rm(bst)
-
-    # load the booster and make predictions...should be the same
-    bst2 <- readRDS.lgb.Booster(file = model_file)
-    preds2 <- predict(bst2, X)
-    expect_identical(preds, preds2)
-})
diff --git a/R-package/tests/testthat/test_lgb.convert_with_rules.R b/R-package/tests/testthat/test_lgb.convert_with_rules.R
deleted file mode 100644
index 546ab9663..000000000
--- a/R-package/tests/testthat/test_lgb.convert_with_rules.R
+++ /dev/null
@@ -1,248 +0,0 @@
-context("lgb.convert_with_rules()")
-
-test_that("lgb.convert_with_rules() rejects inputs that are not a data.table or data.frame", {
-    bad_inputs <- list(
-        matrix(1.0:10.0, 2L, 5L)
-        , TRUE
-        , c("a", "b")
-        , NA
-        , 10L
-        , lgb.Dataset(
-            data = matrix(1.0:10.0, 2L, 5L)
-            , params = list()
-        )
-    )
-    for (bad_input in bad_inputs) {
-        expect_error({
-            conversion_result <- lgb.convert_with_rules(bad_input)
-        }, regexp = "lgb.convert_with_rules: you provided", fixed = TRUE)
-    }
-})
-
-test_that("lgb.convert_with_rules() should work correctly for a dataset with only character columns", {
-    testDF <- data.frame(
-        col1 = c("a", "b", "c")
-        , col2 =  c("green", "green", "red")
-        , stringsAsFactors = FALSE
-    )
-    testDT <- data.table::as.data.table(testDF)
-    for (input_data in list(testDF, testDT)) {
-        conversion_result <- lgb.convert_with_rules(input_data)
-        # dataset should have been converted to integer
-        converted_dataset <- conversion_result[["data"]]
-        expect_identical(class(input_data), class(converted_dataset))
-        expect_identical(class(converted_dataset[["col1"]]), "integer")
-        expect_identical(class(converted_dataset[["col2"]]), "integer")
-        expect_identical(converted_dataset[["col1"]], c(1L, 2L, 3L))
-        expect_identical(converted_dataset[["col2"]], c(1L, 1L, 2L))
-        # rules should be returned and correct
-        rules <- conversion_result$rules
-        expect_is(rules, "list")
-        expect_length(rules, ncol(input_data))
-        expect_identical(rules[["col1"]], c("a" = 1L, "b" = 2L, "c" = 3L))
-        expect_identical(rules[["col2"]], c("green" = 1L, "red" = 2L))
-    }
-})
-
-test_that("lgb.convert_with_rules() should work correctly for a dataset with only factor columns", {
-    testDF <- data.frame(
-        col1 = as.factor(c("a", "b", "c"))
-        , col2 =  as.factor(c("green", "green", "red"))
-        , stringsAsFactors = FALSE
-    )
-    testDT <- data.table::as.data.table(testDF)
-    for (input_data in list(testDF, testDT)) {
-        conversion_result <- lgb.convert_with_rules(input_data)
-        # dataset should have been converted to integer
-        converted_dataset <- conversion_result[["data"]]
-        expect_identical(class(input_data), class(converted_dataset))
-        expect_identical(class(converted_dataset[["col1"]]), "integer")
-        expect_identical(class(converted_dataset[["col2"]]), "integer")
-        expect_identical(converted_dataset[["col1"]], c(1L, 2L, 3L))
-        expect_identical(converted_dataset[["col2"]], c(1L, 1L, 2L))
-        # rules should be returned and correct
-        rules <- conversion_result$rules
-        expect_is(rules, "list")
-        expect_length(rules, ncol(input_data))
-        expect_identical(rules[["col1"]], c("a" = 1L, "b" = 2L, "c" = 3L))
-        expect_identical(rules[["col2"]], c("green" = 1L, "red" = 2L))
-    }
-})
-
-test_that("lgb.convert_with_rules() should not change a dataset with only integer columns", {
-    testDF <- data.frame(
-        col1 = 11L:15L
-        , col2 = 16L:20L
-        , stringsAsFactors = FALSE
-    )
-    testDT <- data.table::as.data.table(testDF)
-    for (input_data in list(testDF, testDT)) {
-        conversion_result <- lgb.convert_with_rules(input_data)
-        # dataset should have been converted to integer
-        converted_dataset <- conversion_result[["data"]]
-        expect_identical(converted_dataset, input_data)
-        # rules should be returned and correct
-        rules <- conversion_result$rules
-        expect_identical(rules, list())
-    }
-})
-
-test_that("lgb.convert_with_rules() should work correctly for a dataset with numeric, factor, and character columns", {
-    testDF <- data.frame(
-        character_col = c("a", "b", "c")
-        , numeric_col = c(1.0, 9.0, 10.0)
-        , factor_col = as.factor(c("n", "n", "y"))
-        , stringsAsFactors = FALSE
-    )
-    testDT <- data.table::as.data.table(testDF)
-    for (input_data in list(testDF, testDT)) {
-        conversion_result <- lgb.convert_with_rules(input_data)
-        # dataset should have been converted to numeric
-        converted_dataset <- conversion_result[["data"]]
-        expect_identical(class(input_data), class(converted_dataset))
-        expect_identical(class(converted_dataset[["character_col"]]), "integer")
-        expect_identical(class(converted_dataset[["factor_col"]]), "integer")
-        expect_identical(converted_dataset[["character_col"]], c(1L, 2L, 3L))
-        expect_identical(converted_dataset[["factor_col"]], c(1L, 1L, 2L))
-        # rules should be returned and correct
-        rules <- conversion_result$rules
-        expect_is(rules, "list")
-        expect_length(rules, 2L)
-        expect_identical(rules[["character_col"]], c("a" = 1L, "b" = 2L, "c" = 3L))
-        expect_identical(rules[["factor_col"]], c("n" = 1L, "y" = 2L))
-
-        # today, lgb.convert_with_rules() does not convert numeric columns
-        expect_identical(class(converted_dataset[["numeric_col"]]), "numeric")
-        expect_identical(converted_dataset[["numeric_col"]], c(1.0, 9.0, 10.0))
-    }
-})
-
-test_that("lgb.convert_with_rules() should convert missing values to the expected value", {
-    testDF <- data.frame(
-        character_col = c("a", NA_character_, "c")
-        , na_col = rep(NA, 3L)
-        , na_real_col = rep(NA_real_, 3L)
-        , na_int_col = rep(NA_integer_,  3L)
-        , na_character_col = rep(NA_character_, 3L)
-        , numeric_col = c(1.0, 9.0, NA_real_)
-        , factor_col = as.factor(c("n", "n", "y"))
-        , integer_col = c(1L, 9L, NA_integer_)
-        , stringsAsFactors = FALSE
-    )
-    testDT <- data.table::as.data.table(testDF)
-    for (input_data in list(testDF, testDT)) {
-        conversion_result <- lgb.convert_with_rules(input_data)
-        # dataset should have been converted to integer
-        converted_dataset <- conversion_result[["data"]]
-        expect_identical(class(input_data), class(converted_dataset))
-
-        expect_identical(class(converted_dataset[["character_col"]]), "integer")
-        expect_identical(converted_dataset[["character_col"]], c(1L, 0L, 2L))
-
-        # does not try to fill 0s in for already-integer columns
-        expect_identical(class(converted_dataset[["integer_col"]]), "integer")
-        expect_identical(converted_dataset[["integer_col"]], c(1L, 9L, NA_integer_))
-        expect_identical(class(converted_dataset[["na_int_col"]]), "integer")
-        expect_identical(converted_dataset[["na_int_col"]], rep(NA_integer_, nrow(converted_dataset)))
-
-        expect_identical(class(converted_dataset[["factor_col"]]), "integer")
-        expect_identical(converted_dataset[["factor_col"]], c(1L, 1L, 2L))
-
-        # NAs in character columns should be converted to 0
-        expect_identical(class(converted_dataset[["na_character_col"]]), "integer")
-        expect_identical(converted_dataset[["na_character_col"]], rep(0L, nrow(converted_dataset)))
-
-        # logical should be converted to integer
-        expect_identical(class(converted_dataset[["na_col"]]), "integer")
-        expect_identical(converted_dataset[["na_col"]], rep(-1L, 3L))
-
-        # lgb.convert_with_rules() should not convert numeric columns to integer
-        expect_identical(class(converted_dataset[["na_real_col"]]), "numeric")
-        expect_identical(converted_dataset[["na_real_col"]], rep(NA_real_, nrow(converted_dataset)))
-        expect_identical(class(converted_dataset[["numeric_col"]]), "numeric")
-        expect_identical(converted_dataset[["numeric_col"]], c(1.0, 9.0, NA_real_))
-
-        # rules should be returned and correct
-        rules <- conversion_result$rules
-        expect_is(rules, "list")
-        expect_length(rules, 3L)
-        expect_identical(rules[["character_col"]], c("a" = 1L, "c" = 2L))
-        expect_identical(rules[["factor_col"]], c("n" = 1L, "y" = 2L))
-        expect_identical(rules[["na_col"]], stats::setNames(c(0L, 1L), c(FALSE, TRUE)))
-    }
-})
-
-test_that("lgb.convert_with_rules() should work correctly if you provide your own well-formed rules", {
-    testDF <- data.frame(
-        character_col = c("a", NA_character_, "c", "a", "a", "c")
-        , na_col = rep(NA, 6L)
-        , na_real_col = rep(NA_real_, 6L)
-        , na_int_col = rep(NA_integer_, 6L)
-        , na_character_col = rep(NA_character_, 6L)
-        , numeric_col = c(1.0, 9.0, NA_real_, 10.0, 11.0, 12.0)
-        , factor_col = as.factor(c("n", "n", "y", "y", "n", "n"))
-        , integer_col = c(1L, 9L, NA_integer_, 1L, 1L, 1L)
-        , stringsAsFactors = FALSE
-    )
-    testDT <- data.table::as.data.table(testDF)
-
-    # value used by lgb.convert_with_rules() when it encounters a categorical value that
-    # is not in the provided rules
-    UNKNOWN_FACTOR_VALUE <- 0L
-    UNKNOWN_LOGICAL_VALUE <- -1L
-    for (input_data in list(testDF, testDT)) {
-        custom_rules <- list(
-            "character_col" = c(
-                "a" = 5L
-                , "c" = -10L
-            )
-            , "factor_col" = c(
-                "n" = 65L
-                , "y" = 66L
-            )
-        )
-        conversion_result <- lgb.convert_with_rules(
-            data = input_data
-            , rules = custom_rules
-        )
-
-        # dataset should have been converted to integer
-        converted_dataset <- conversion_result[["data"]]
-        expect_identical(class(input_data), class(converted_dataset))
-
-        expect_identical(class(converted_dataset[["character_col"]]), "integer")
-        expect_identical(converted_dataset[["character_col"]], c(5L, UNKNOWN_FACTOR_VALUE, -10L, 5L, 5L, -10L))
-
-        expect_identical(class(converted_dataset[["factor_col"]]), "integer")
-        expect_identical(converted_dataset[["factor_col"]], c(65L, 65L, 66L, 66L, 65L, 65L))
-
-        # columns not specified in rules are not going to be converted, unless they are all NA
-        for (col in c("na_real_col", "na_int_col", "numeric_col", "integer_col")) {
-            expect_identical(converted_dataset[[col]], input_data[[col]])
-        }
-
-        # non-numeric/integer columns that are all NA should have been filled in
-        expect_identical(converted_dataset[["na_col"]], rep(UNKNOWN_LOGICAL_VALUE, 6L))
-        expect_identical(converted_dataset[["na_character_col"]], rep(UNKNOWN_FACTOR_VALUE, 6L))
-
-        # the rules you passed in should be returned unchanged
-        rules <- conversion_result$rules
-        expect_identical(rules, custom_rules)
-    }
-})
-
-test_that("lgb.convert_with_rules() should modify data.tables in-place", {
-    testDT <- data.table::data.table(
-        character_col = c("a", NA_character_, "c")
-        , na_col = rep(NA, 3L)
-        , na_real_col = rep(NA_real_, 3L)
-        , na_int_col = rep(NA_integer_,  3L)
-        , na_character_col = rep(NA_character_, 3L)
-        , numeric_col = c(1.0, 9.0, NA_real_)
-        , factor_col = as.factor(c("n", "n", "y"))
-        , integer_col = c(1L, 9L, NA_integer_)
-    )
-    conversion_result <- lgb.convert_with_rules(testDT)
-    resultDT <- conversion_result[["data"]]
-    expect_identical(resultDT, testDT)
-})
diff --git a/R-package/tests/testthat/test_lgb.importance.R b/R-package/tests/testthat/test_lgb.importance.R
deleted file mode 100644
index c0e1d6e8c..000000000
--- a/R-package/tests/testthat/test_lgb.importance.R
+++ /dev/null
@@ -1,39 +0,0 @@
-context("lgb.importance")
-
-test_that("lgb.importance() should reject bad inputs", {
-    bad_inputs <- list(
-        .Machine$integer.max
-        , Inf
-        , -Inf
-        , NA
-        , NA_real_
-        , -10L:10L
-        , list(c("a", "b", "c"))
-        , data.frame(
-            x = rnorm(20L)
-            , y = sample(
-                x = c(1L, 2L)
-                , size = 20L
-                , replace = TRUE
-            )
-        )
-        , data.table::data.table(
-            x = rnorm(20L)
-            , y = sample(
-                x = c(1L, 2L)
-                , size = 20L
-                , replace = TRUE
-            )
-        )
-        , lgb.Dataset(
-            data = matrix(rnorm(100L), ncol = 2L)
-            , label = matrix(sample(c(0L, 1L), 50L, replace = TRUE))
-        )
-        , "lightgbm.model"
-    )
-    for (input in bad_inputs) {
-        expect_error({
-            lgb.importance(input)
-        }, regexp = "'model' has to be an object of class lgb\\.Booster")
-    }
-})
diff --git a/R-package/tests/testthat/test_lgb.interprete.R b/R-package/tests/testthat/test_lgb.interprete.R
deleted file mode 100644
index bf113db43..000000000
--- a/R-package/tests/testthat/test_lgb.interprete.R
+++ /dev/null
@@ -1,113 +0,0 @@
-context("lgb.interpete")
-
-.sigmoid <- function(x) {
-    1.0 / (1.0 + exp(-x))
-}
-.logit <- function(x) {
-    log(x / (1.0 - x))
-}
-
-test_that("lgb.intereprete works as expected for binary classification", {
-    data(agaricus.train, package = "lightgbm")
-    train <- agaricus.train
-    dtrain <- lgb.Dataset(train$data, label = train$label)
-    setinfo(
-        dataset = dtrain
-        , "init_score"
-        , rep(
-            .logit(mean(train$label))
-            , length(train$label)
-        )
-    )
-    data(agaricus.test, package = "lightgbm")
-    test <- agaricus.test
-    params <- list(
-        objective = "binary"
-        , learning_rate = 0.01
-        , num_leaves = 63L
-        , max_depth = -1L
-        , min_data_in_leaf = 1L
-        , min_sum_hessian_in_leaf = 1.0
-    )
-    model <- lgb.train(
-        params = params
-        , data = dtrain
-        , nrounds = 3L
-    )
-    num_trees <- 5L
-    tree_interpretation <- lgb.interprete(
-        model = model
-        , data = test$data
-        , idxset = seq_len(num_trees)
-    )
-    expect_identical(class(tree_interpretation), "list")
-    expect_true(length(tree_interpretation) == num_trees)
-    expect_null(names(tree_interpretation))
-    expect_true(all(
-        sapply(
-            X = tree_interpretation
-            , FUN = function(treeDT) {
-                checks <- c(
-                    data.table::is.data.table(treeDT)
-                    , identical(names(treeDT), c("Feature", "Contribution"))
-                    , is.character(treeDT[, Feature])
-                    , is.numeric(treeDT[, Contribution])
-                )
-                return(all(checks))
-            }
-        )
-    ))
-})
-
-test_that("lgb.intereprete works as expected for multiclass classification", {
-    data(iris)
-
-    # We must convert factors to numeric
-    # They must be starting from number 0 to use multiclass
-    # For instance: 0, 1, 2, 3, 4, 5...
-    iris$Species <- as.numeric(as.factor(iris$Species)) - 1L
-
-    # Create imbalanced training data (20, 30, 40 examples for classes 0, 1, 2)
-    train <- as.matrix(iris[c(1L:20L, 51L:80L, 101L:140L), ])
-    # The 10 last samples of each class are for validation
-    test <- as.matrix(iris[c(41L:50L, 91L:100L, 141L:150L), ])
-    dtrain <- lgb.Dataset(data = train[, 1L:4L], label = train[, 5L])
-    dtest <- lgb.Dataset.create.valid(dtrain, data = test[, 1L:4L], label = test[, 5L])
-    params <- list(
-        objective = "multiclass"
-        , metric = "multi_logloss"
-        , num_class = 3L
-        , learning_rate = 0.00001
-    )
-    model <- lgb.train(
-        params = params
-        , data = dtrain
-        , nrounds = 3L
-        , min_data = 1L
-    )
-    num_trees <- 5L
-    tree_interpretation <- lgb.interprete(
-        model = model
-        , data = test[, 1L:4L]
-        , idxset = seq_len(num_trees)
-    )
-    expect_identical(class(tree_interpretation), "list")
-    expect_true(length(tree_interpretation) == num_trees)
-    expect_null(names(tree_interpretation))
-    expect_true(all(
-        sapply(
-            X = tree_interpretation
-            , FUN = function(treeDT) {
-                checks <- c(
-                    data.table::is.data.table(treeDT)
-                    , identical(names(treeDT), c("Feature", "Class 0", "Class 1", "Class 2"))
-                    , is.character(treeDT[, Feature])
-                    , is.numeric(treeDT[, `Class 0`])
-                    , is.numeric(treeDT[, `Class 1`])
-                    , is.numeric(treeDT[, `Class 2`])
-                )
-                return(all(checks))
-            }
-        )
-    ))
-})
diff --git a/R-package/tests/testthat/test_lgb.plot.importance.R b/R-package/tests/testthat/test_lgb.plot.importance.R
deleted file mode 100644
index 1f71117ab..000000000
--- a/R-package/tests/testthat/test_lgb.plot.importance.R
+++ /dev/null
@@ -1,47 +0,0 @@
-context("lgb.plot.importance()")
-
-test_that("lgb.plot.importance() should run without error for well-formed inputs", {
-    data(agaricus.train, package = "lightgbm")
-    train <- agaricus.train
-    dtrain <- lgb.Dataset(train$data, label = train$label)
-    params <- list(
-        objective = "binary"
-        , learning_rate = 0.01
-        , num_leaves = 63L
-        , max_depth = -1L
-        , min_data_in_leaf = 1L
-        , min_sum_hessian_in_leaf = 1.0
-    )
-    model <- lgb.train(params, dtrain, 3L)
-    tree_imp <- lgb.importance(model, percentage = TRUE)
-
-    # Check that there are no plots present before plotting
-    expect_null(dev.list())
-
-    args_no_cex <- list(
-        "tree_imp" = tree_imp
-        , top_n = 10L
-        , measure = "Gain"
-    )
-    args_cex <- args_no_cex
-    args_cex[["cex"]] <- 0.75
-
-    for (arg_list in list(args_no_cex, args_cex)) {
-
-        resDT <- do.call(
-            what = lgb.plot.importance
-            , args = arg_list
-        )
-
-        # Check that lgb.plot.importance() returns the data.table of the plotted data
-        expect_true(data.table::is.data.table(resDT))
-        expect_named(resDT, c("Feature", "Gain", "Cover", "Frequency"))
-
-        # Check that a plot was produced
-        expect_false(is.null(dev.list()))
-
-        # remove all plots
-        dev.off()
-        expect_null(dev.list())
-    }
-})
diff --git a/R-package/tests/testthat/test_lgb.plot.interpretation.R b/R-package/tests/testthat/test_lgb.plot.interpretation.R
deleted file mode 100644
index be51e2fc9..000000000
--- a/R-package/tests/testthat/test_lgb.plot.interpretation.R
+++ /dev/null
@@ -1,97 +0,0 @@
-context("lgb.plot.interpretation")
-
-.sigmoid <- function(x) {
-    1.0 / (1.0 + exp(-x))
-}
-.logit <- function(x) {
-    log(x / (1.0 - x))
-}
-
-test_that("lgb.plot.interepretation works as expected for binary classification", {
-    data(agaricus.train, package = "lightgbm")
-    train <- agaricus.train
-    dtrain <- lgb.Dataset(train$data, label = train$label)
-    setinfo(
-        dataset = dtrain
-        , "init_score"
-        , rep(
-            .logit(mean(train$label))
-            , length(train$label)
-        )
-    )
-    data(agaricus.test, package = "lightgbm")
-    test <- agaricus.test
-    params <- list(
-        objective = "binary"
-        , learning_rate = 0.01
-        , num_leaves = 63L
-        , max_depth = -1L
-        , min_data_in_leaf = 1L
-        , min_sum_hessian_in_leaf = 1.0
-    )
-    model <- lgb.train(
-        params = params
-        , data = dtrain
-        , nrounds = 3L
-    )
-    num_trees <- 5L
-    tree_interpretation <- lgb.interprete(
-        model = model
-        , data = test$data
-        , idxset = seq_len(num_trees)
-    )
-    expect_true({
-        lgb.plot.interpretation(
-            tree_interpretation_dt = tree_interpretation[[1L]]
-            , top_n = 5L
-        )
-        TRUE
-    })
-
-    # should also work when you explicitly pass cex
-    plot_res <- lgb.plot.interpretation(
-        tree_interpretation_dt = tree_interpretation[[1L]]
-        , top_n = 5L
-        , cex = 0.95
-    )
-    expect_null(plot_res)
-})
-
-test_that("lgb.plot.interepretation works as expected for multiclass classification", {
-    data(iris)
-
-    # We must convert factors to numeric
-    # They must be starting from number 0 to use multiclass
-    # For instance: 0, 1, 2, 3, 4, 5...
-    iris$Species <- as.numeric(as.factor(iris$Species)) - 1L
-
-    # Create imbalanced training data (20, 30, 40 examples for classes 0, 1, 2)
-    train <- as.matrix(iris[c(1L:20L, 51L:80L, 101L:140L), ])
-    # The 10 last samples of each class are for validation
-    test <- as.matrix(iris[c(41L:50L, 91L:100L, 141L:150L), ])
-    dtrain <- lgb.Dataset(data = train[, 1L:4L], label = train[, 5L])
-    dtest <- lgb.Dataset.create.valid(dtrain, data = test[, 1L:4L], label = test[, 5L])
-    params <- list(
-        objective = "multiclass"
-        , metric = "multi_logloss"
-        , num_class = 3L
-        , learning_rate = 0.00001
-    )
-    model <- lgb.train(
-        params = params
-        , data = dtrain
-        , nrounds = 3L
-        , min_data = 1L
-    )
-    num_trees <- 5L
-    tree_interpretation <- lgb.interprete(
-        model = model
-        , data = test[, 1L:4L]
-        , idxset = seq_len(num_trees)
-    )
-    plot_res <- lgb.plot.interpretation(
-        tree_interpretation_dt = tree_interpretation[[1L]]
-        , top_n = 5L
-    )
-    expect_null(plot_res)
-})
diff --git a/R-package/tests/testthat/test_lgb.unloader.R b/R-package/tests/testthat/test_lgb.unloader.R
deleted file mode 100644
index 9eaa9adb8..000000000
--- a/R-package/tests/testthat/test_lgb.unloader.R
+++ /dev/null
@@ -1,52 +0,0 @@
-context("lgb.unloader")
-
-test_that("lgb.unloader works as expected", {
-    data(agaricus.train, package = "lightgbm")
-    train <- agaricus.train
-    dtrain <- lgb.Dataset(train$data, label = train$label)
-    bst <- lgb.train(
-        params = list(
-            objective = "regression"
-            , metric = "l2"
-        )
-        , data = dtrain
-        , nrounds = 1L
-        , min_data = 1L
-        , learning_rate = 1.0
-    )
-    expect_true(exists("bst"))
-    result <- lgb.unloader(restore = TRUE, wipe = TRUE, envir = environment())
-    expect_false(exists("bst"))
-    expect_null(result)
-})
-
-test_that("lgb.unloader finds all boosters and removes them", {
-    data(agaricus.train, package = "lightgbm")
-    train <- agaricus.train
-    dtrain <- lgb.Dataset(train$data, label = train$label)
-    bst1 <- lgb.train(
-        params = list(
-            objective = "regression"
-            , metric = "l2"
-        )
-        , data = dtrain
-        , nrounds = 1L
-        , min_data = 1L
-        , learning_rate = 1.0
-    )
-    bst2 <- lgb.train(
-        params = list(
-            objective = "regression"
-            , metric = "l2"
-        )
-        , data = dtrain
-        , nrounds = 1L
-        , min_data = 1L
-        , learning_rate = 1.0
-    )
-    expect_true(exists("bst1"))
-    expect_true(exists("bst2"))
-    lgb.unloader(restore = TRUE, wipe = TRUE, envir = environment())
-    expect_false(exists("bst1"))
-    expect_false(exists("bst2"))
-})
diff --git a/R-package/tests/testthat/test_metrics.R b/R-package/tests/testthat/test_metrics.R
deleted file mode 100644
index 73f60c5f8..000000000
--- a/R-package/tests/testthat/test_metrics.R
+++ /dev/null
@@ -1,12 +0,0 @@
-context(".METRICS_HIGHER_BETTER()")
-
-test_that(".METRICS_HIGHER_BETTER() should be well formed", {
-    metrics <- .METRICS_HIGHER_BETTER()
-    metric_names <- names(.METRICS_HIGHER_BETTER())
-    # should be a logical vector
-    expect_true(is.logical(metrics))
-    # no metrics should be repeated
-    expect_true(length(unique(metric_names)) == length(metrics))
-    # should not be any NAs
-    expect_false(any(is.na(metrics)))
-})
diff --git a/R-package/tests/testthat/test_parameters.R b/R-package/tests/testthat/test_parameters.R
deleted file mode 100644
index 16d1e4a5a..000000000
--- a/R-package/tests/testthat/test_parameters.R
+++ /dev/null
@@ -1,83 +0,0 @@
-
-context("feature penalties")
-
-data(agaricus.train, package = "lightgbm")
-data(agaricus.test, package = "lightgbm")
-train <- agaricus.train
-test <- agaricus.test
-
-test_that("Feature penalties work properly", {
-  # Fit a series of models with varying penalty on most important variable
-  var_name <- "odor=none"
-  var_index <- which(train$data@Dimnames[[2L]] == var_name)
-
-  bst <- lapply(seq(1.0, 0.0, by = -0.1), function(x) {
-    feature_penalties <- rep(1.0, ncol(train$data))
-    feature_penalties[var_index] <- x
-    lightgbm(
-      data = train$data
-      , label = train$label
-      , num_leaves = 5L
-      , learning_rate = 0.05
-      , nrounds = 5L
-      , objective = "binary"
-      , feature_penalty = paste0(feature_penalties, collapse = ",")
-      , metric = "binary_error"
-      , verbose = -1L
-      , save_name = tempfile(fileext = ".model")
-    )
-  })
-
-  var_gain <- lapply(bst, function(x) lgb.importance(x)[Feature == var_name, Gain])
-  var_cover <- lapply(bst, function(x) lgb.importance(x)[Feature == var_name, Cover])
-  var_freq <- lapply(bst, function(x) lgb.importance(x)[Feature == var_name, Frequency])
-
-  # Ensure that feature gain, cover, and frequency decreases with stronger penalties
-  expect_true(all(diff(unlist(var_gain)) <= 0.0))
-  expect_true(all(diff(unlist(var_cover)) <= 0.0))
-  expect_true(all(diff(unlist(var_freq)) <= 0.0))
-
-  expect_lt(min(diff(unlist(var_gain))), 0.0)
-  expect_lt(min(diff(unlist(var_cover))), 0.0)
-  expect_lt(min(diff(unlist(var_freq))), 0.0)
-
-  # Ensure that feature is not used when feature_penalty = 0
-  expect_length(var_gain[[length(var_gain)]], 0L)
-})
-
-context("parameter aliases")
-
-test_that(".PARAMETER_ALIASES() returns a named list of character vectors, where names are unique", {
-  param_aliases <- .PARAMETER_ALIASES()
-  expect_identical(class(param_aliases), "list")
-  expect_true(is.character(names(param_aliases)))
-  expect_true(is.character(param_aliases[["boosting"]]))
-  expect_true(is.character(param_aliases[["early_stopping_round"]]))
-  expect_true(is.character(param_aliases[["num_iterations"]]))
-  expect_true(is.character(param_aliases[["pre_partition"]]))
-  expect_true(length(names(param_aliases)) == length(param_aliases))
-  expect_true(all(sapply(param_aliases, is.character)))
-  expect_true(length(unique(names(param_aliases))) == length(param_aliases))
-})
-
-test_that("training should warn if you use 'dart' boosting, specified with 'boosting' or aliases", {
-  for (boosting_param in .PARAMETER_ALIASES()[["boosting"]]) {
-    expect_warning({
-      result <- lightgbm(
-        data = train$data
-        , label = train$label
-        , num_leaves = 5L
-        , learning_rate = 0.05
-        , nrounds = 5L
-        , objective = "binary"
-        , metric = "binary_error"
-        , verbose = -1L
-        , params = stats::setNames(
-          object = "dart"
-          , nm = boosting_param
-        )
-        , save_name = tempfile(fileext = ".model")
-      )
-    }, regexp = "Early stopping is not available in 'dart' mode")
-  }
-})
diff --git a/R-package/tests/testthat/test_utils.R b/R-package/tests/testthat/test_utils.R
deleted file mode 100644
index 228de3636..000000000
--- a/R-package/tests/testthat/test_utils.R
+++ /dev/null
@@ -1,187 +0,0 @@
-context("lgb.encode.char")
-
-test_that("lgb.encode.char throws an informative error if it is passed a non-raw input", {
-    x <- "some-string"
-    expect_error({
-        lgb.encode.char(x)
-    }, regexp = "Can only encode from raw type")
-})
-
-context("lgb.check.r6.class")
-
-test_that("lgb.check.r6.class() should return FALSE for NULL input", {
-    expect_false(lgb.check.r6.class(NULL, "lgb.Dataset"))
-})
-
-test_that("lgb.check.r6.class() should return FALSE for non-R6 inputs", {
-    x <- 5L
-    class(x) <- "lgb.Dataset"
-    expect_false(lgb.check.r6.class(x, "lgb.Dataset"))
-})
-
-test_that("lgb.check.r6.class() should correctly identify lgb.Dataset", {
-
-    data("agaricus.train", package = "lightgbm")
-    train <- agaricus.train
-    ds <- lgb.Dataset(train$data, label = train$label)
-    expect_true(lgb.check.r6.class(ds, "lgb.Dataset"))
-    expect_false(lgb.check.r6.class(ds, "lgb.Predictor"))
-    expect_false(lgb.check.r6.class(ds, "lgb.Booster"))
-})
-
-context("lgb.params2str")
-
-test_that("lgb.params2str() works as expected for empty lists", {
-    out_str <- lgb.params2str(
-        params = list()
-    )
-    expect_identical(class(out_str), "character")
-    expect_equal(out_str, "")
-})
-
-test_that("lgb.params2str() works as expected for a key in params with multiple different-length elements", {
-    metrics <- c("a", "ab", "abc", "abcdefg")
-    params <- list(
-        objective = "magic"
-        , metric = metrics
-        , nrounds = 10L
-        , learning_rate = 0.0000001
-    )
-    out_str <- lgb.params2str(
-        params = params
-    )
-    expect_identical(class(out_str), "character")
-    expect_identical(
-        out_str
-        , "objective=magic metric=a,ab,abc,abcdefg nrounds=10 learning_rate=0.0000001"
-    )
-})
-
-context("lgb.last_error")
-
-test_that("lgb.last_error() throws an error if there are no errors", {
-    expect_error({
-        lgb.last_error()
-    }, regexp = "Everything is fine")
-})
-
-test_that("lgb.last_error() correctly returns errors from the C++ side", {
-    testthat::skip(paste0(
-        "Skipping this test because it causes valgrind to think "
-        , "there is a memory leak, and needs to be rethought"
-    ))
-    data(agaricus.train, package = "lightgbm")
-    train <- agaricus.train
-    dvalid1 <- lgb.Dataset(
-        data = train$data
-        , label = as.matrix(rnorm(5L))
-    )
-    expect_error({
-        dvalid1$construct()
-    }, regexp = "[LightGBM] [Fatal] Length of label is not same with #data", fixed = TRUE)
-})
-
-context("lgb.check.eval")
-
-test_that("lgb.check.eval works as expected with no metric", {
-    params <- lgb.check.eval(
-        params = list(device = "cpu")
-        , eval = "binary_error"
-    )
-    expect_named(params, c("device", "metric"))
-    expect_identical(params[["metric"]], list("binary_error"))
-})
-
-test_that("lgb.check.eval adds eval to metric in params", {
-    params <- lgb.check.eval(
-        params = list(metric = "auc")
-        , eval = "binary_error"
-    )
-    expect_named(params, "metric")
-    expect_identical(params[["metric"]], list("auc", "binary_error"))
-})
-
-test_that("lgb.check.eval adds eval to metric in params if two evaluation names are provided", {
-    params <- lgb.check.eval(
-        params = list(metric = "auc")
-        , eval = c("binary_error", "binary_logloss")
-    )
-    expect_named(params, "metric")
-    expect_identical(params[["metric"]], list("auc", "binary_error", "binary_logloss"))
-})
-
-test_that("lgb.check.eval adds eval to metric in params if a list is provided", {
-    params <- lgb.check.eval(
-        params = list(metric = "auc")
-        , eval = list("binary_error", "binary_logloss")
-    )
-    expect_named(params, "metric")
-    expect_identical(params[["metric"]], list("auc", "binary_error", "binary_logloss"))
-})
-
-test_that("lgb.check.eval drops duplicate metrics and preserves order", {
-    params <- lgb.check.eval(
-        params = list(metric = "l1")
-        , eval = list("l2", "rmse", "l1", "rmse")
-    )
-    expect_named(params, "metric")
-    expect_identical(params[["metric"]], list("l1", "l2", "rmse"))
-})
-
-context("lgb.check.wrapper_param")
-
-test_that("lgb.check.wrapper_param() uses passed-in keyword arg if no alias found in params", {
-    kwarg_val <- sample(seq_len(100L), size = 1L)
-    params <- lgb.check.wrapper_param(
-        main_param_name = "num_iterations"
-        , params = list()
-        , alternative_kwarg_value = kwarg_val
-    )
-    expect_equal(params[["num_iterations"]], kwarg_val)
-})
-
-test_that("lgb.check.wrapper_param() prefers main parameter to alias and keyword arg", {
-    num_iterations <- sample(seq_len(100L), size = 1L)
-    kwarg_val <- sample(seq_len(100L), size = 1L)
-    params <- lgb.check.wrapper_param(
-        main_param_name = "num_iterations"
-        , params = list(
-            num_iterations = num_iterations
-            , num_tree = sample(seq_len(100L), size = 1L)
-            , n_estimators = sample(seq_len(100L), size = 1L)
-        )
-        , alternative_kwarg_value = kwarg_val
-    )
-    expect_equal(params[["num_iterations"]], num_iterations)
-
-    # aliases should be removed
-    expect_identical(params, list(num_iterations = num_iterations))
-})
-
-test_that("lgb.check.wrapper_param() prefers alias to keyword arg", {
-    n_estimators <- sample(seq_len(100L), size = 1L)
-    num_tree <- sample(seq_len(100L), size = 1L)
-    kwarg_val <- sample(seq_len(100L), size = 1L)
-    params <- lgb.check.wrapper_param(
-        main_param_name = "num_iterations"
-        , params = list(
-            num_tree = num_tree
-            , n_estimators = n_estimators
-        )
-        , alternative_kwarg_value = kwarg_val
-    )
-    expect_equal(params[["num_iterations"]], num_tree)
-    expect_identical(params, list(num_iterations = num_tree))
-
-    # switching the order should switch which one is chosen
-    params2 <- lgb.check.wrapper_param(
-        main_param_name = "num_iterations"
-        , params = list(
-            n_estimators = n_estimators
-            , num_tree = num_tree
-        )
-        , alternative_kwarg_value = kwarg_val
-    )
-    expect_equal(params2[["num_iterations"]], n_estimators)
-    expect_identical(params2, list(num_iterations = n_estimators))
-})