Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error: implement general state_type handler #938

Merged
merged 7 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/specs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This is an index/directory of the specifications (specs) for each new module/fea
- [constants](./stdlib_constants.html) - Constants
- [bitsets](./stdlib_bitsets.html) - Bitset data types and procedures
- [error](./stdlib_error.html) - Catching and handling errors
- [state_type](./stdlib_error_state_type.html) - General state and error handling
- [hash](./stdlib_hash_procedures.html) - Hashing integer
vectors or character strings
- [hashmaps](./stdlib_hashmaps.html) - Hash maps/tables
Expand Down
59 changes: 59 additions & 0 deletions doc/specs/stdlib_error_state_type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
title: state_type
---

# State and Error Handling Derived Type

[TOC]

## Introduction

The `stdlib_error` module provides a derived type holding information on the state of operations within the standard library and procedures for expert control of workflows.
An optional `state_type` variable to hold such information is provided as a form of expert API.
If the user does not require state information but fatal errors are encountered during execution, the program will undergo a hard stop.
Instead, if the state argument is present, the program will never stop but will return detailed error information into the state handler.

## Derived types provided

<!-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -->
### The `state_type` derived type

The `state_type` is defined as a derived type containing an integer error flag and fixed-size character strings to store an error message and the location of the error state change.
Fixed-size string storage was chosen to facilitate the compiler's memory allocation and ultimately ensure maximum computational performance.

A similarly named generic interface, `state_type`, is provided to allow the developer to create diagnostic messages and raise error flags easily.
The call starts with an error flag or the location of the event and is followed by an arbitrary list of `integer`, `real`, `complex`, or `character` variables.
Numeric variables may be provided as either scalars or rank-1 (array) inputs.

#### Type-bound procedures

The following convenience type-bound procedures are provided:
- `print()` returns an allocatable character string containing state location, message, and error flag;
- `print_message()` returns an allocatable character string containing the state message;
- `ok()` returns a `logical` flag that is `.true.` in case of successful state (`flag==STDLIB_SUCCESS`);
- `error()` returns a `logical` flag that is `.true.` in case of an error state (`flag/=STDLIB_SUCCESS`).

#### Status

Experimental

#### Example

```fortran
{!example/error/example_error_state1.f90!}
```

## Error flags provided

The module provides the following state flags:
- `STDLIB_SUCCESS`: Successful execution
- `STDLIB_VALUE_ERROR`: Numerical errors (such as infinity, not-a-number, range bounds) are encountered.
- `STDLIB_LINALG_ERROR`: Linear Algebra errors are encountered, such as non-converging iterations, impossible operations, etc.
- `STDLIB_INTERNAL_ERROR`: Provided as a developer safeguard for internal errors that should never occur.
- `STDLIB_IO_ERROR`: Input/Output-related errors, such as file reading/writing failures.
- `STDLIB_FS_ERROR`: File system-related errors, such as directory access issues.

## Comparison operators provided

The module provides overloaded comparison operators for all comparisons of a `state_type` variable with an integer error flag: `<`, `<=`, `==`, `>=`, `>`, `/=`.

40 changes: 15 additions & 25 deletions doc/specs/stdlib_linalg_state_type.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,27 @@ title: linalg_state_type

## Introduction

The `stdlib_linalg_state` module provides a derived type holding information on the
state of linear algebra operations, and procedures for expert control of linear algebra workflows.
All linear algebra procedures are engineered to support returning an optional `linalg_state_type`
variable to holds such information, as a form of expert API. If the user does not require state
information, but fatal errors are encountered during the execution of linear algebra routines, the
program will undergo a hard stop.
Instead, if the state argument is present, the program will never stop, but will return detailed error
information into the state handler.
The `stdlib_linalg_state` module provides a derived type holding information on the state of linear algebra operations, and procedures for expert control of linear algebra workflows.
All linear algebra procedures are engineered to support returning an optional `linalg_state_type` variable to hold such information, as a form of expert API. If the user does not require state information but fatal errors are encountered during the execution of linear algebra routines, the program will undergo a hard stop.
Instead, if the state argument is present, the program will never stop but will return detailed error information into the state handler.

## Derived types provided

<!-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -->
### The `linalg_state_type` derived type

The `linalg_state_type` is defined as a derived type containing an integer error flag, and
fixed-size character strings to store an error message and the location of the error state change.
Fixed-size string storage was chosen to facilitate the compiler's memory allocation and ultimately
ensure maximum computational performance.
The `linalg_state_type` is an extension of the `state_type` derived type, containing an integer error flag and fixed-size character strings to store an error message and the location of the error state change.
Fixed-size string storage was chosen to facilitate the compiler's memory allocation and ultimately ensure maximum computational performance.

A similarly named generic interface, `linalg_state_type`, is provided to allow the developer to
create diagnostic messages and raise error flags easily. The call starts with an error flag or
the location of the event, and is followed by an arbitrary list of `integer`, `real`, `complex` or
`character` variables. Numeric variables may be provided as either scalars or rank-1 (array) inputs.
A similarly named generic interface, `linalg_state_type`, is provided to allow the developer to create diagnostic messages and raise error flags easily. The call starts with an error flag or the location of the event and is followed by an arbitrary list of `integer`, `real`, `complex`, or `character` variables. Numeric variables may be provided as either scalars or rank-1 (array) inputs.

#### Type-bound procedures

The following convenience type-bound procedures are provided:
The following convenience type-bound procedures are inherited from `state_type` and available:
- `print()` returns an allocatable character string containing state location, message, and error flag;
- `print_message()` returns an allocatable character string containing the state message;
- `ok()` returns a `logical` flag that is `.true.` in case of successful state (`flag==LINALG_SUCCESS`);
- `error()` returns a `logical` flag that is `.true.` in case of error state (`flag/=LINALG_SUCCESS`).
- `error()` returns a `logical` flag that is `.true.` in case of an error state (`flag/=LINALG_SUCCESS`).

#### Status

Expand All @@ -52,13 +42,13 @@ Experimental

## Error flags provided

The module provides the following state flags:
- `LINALG_SUCCESS`: Successful execution
- `LINALG_VALUE_ERROR`: Numerical errors (such as infinity, not-a-number, range bounds) are encountered.
- `LINALG_ERROR`: Linear Algebra errors are encountered, such as: non-converging iterations, impossible operations, etc.
- `LINALG_INTERNAL_ERROR`: Provided as a developer safeguard for internal errors that should never occur.
The module provides the following state flags, mapped to the general `state_type` error flags:
- `LINALG_SUCCESS`: Successful execution (equivalent to `STDLIB_SUCCESS`)
- `LINALG_VALUE_ERROR`: Numerical errors (such as infinity, not-a-number, range bounds) are encountered (equivalent to `STDLIB_VALUE_ERROR`).
- `LINALG_ERROR`: Linear Algebra errors are encountered, such as non-converging iterations, impossible operations, etc. (equivalent to `STDLIB_LINALG_ERROR`).
- `LINALG_INTERNAL_ERROR`: Provided as a developer safeguard for internal errors that should never occur (equivalent to `STDLIB_INTERNAL_ERROR`).

## Comparison operators provided

The module provides overloaded comparison operators for all comparisons of a `linalg_state_type` variable
with an integer error flag: `<`, `<=`, `==`, `>=`, `>`, `/=`.
The module provides overloaded comparison operators for all comparisons of a `linalg_state_type` variable with an integer error flag: `<`, `<=`, `==`, `>=`, `>`, `/=`.

2 changes: 2 additions & 0 deletions example/error/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ ADD_EXAMPLE(error_stop1)
set_tests_properties(error_stop1 PROPERTIES WILL_FAIL true)
ADD_EXAMPLE(error_stop2)
set_tests_properties(error_stop2 PROPERTIES WILL_FAIL true)
ADD_EXAMPLE(error_state1)
ADD_EXAMPLE(error_state2)
18 changes: 18 additions & 0 deletions example/error/example_error_state1.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
program example_error_state1
use stdlib_error, only: state_type, STDLIB_VALUE_ERROR, STDLIB_SUCCESS, operator(/=)
implicit none
type(state_type) :: err

! To create a state variable, we enter its integer state flag, followed by a list of variables
! that will be automatically assembled into a formatted error message. No need to provide string formats
err = state_type(STDLIB_VALUE_ERROR,'just an example with scalar ',&
'integer=',1,'real=',2.0,'complex=',(3.0,1.0),'and array ',[1,2,3],'inputs')

! Print flag
print *, err%print()

! Check success
print *, 'Check error: ',err%error()
print *, 'Check flag : ',err /= STDLIB_SUCCESS

end program example_error_state1
62 changes: 62 additions & 0 deletions example/error/example_error_state2.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
program example_error_state2
!! This example shows how to set a `type(state_type)` variable to process output conditions
!! out of a simple division routine. The example is meant to highlight:
!! 1) the different mechanisms that can be used to initialize the `state_type` variable providing
!! strings, scalars, or arrays, on input to it;
!! 2) `pure` setup of the error control
use stdlib_error, only: state_type, STDLIB_VALUE_ERROR, STDLIB_SUCCESS
implicit none
type(state_type) :: err
real :: a_div_b

! OK
call very_simple_division(0.0,2.0,a_div_b,err)
print *, err%print()

! Division by zero
call very_simple_division(1.0,0.0,a_div_b,err)
print *, err%print()

! Out of bounds
call very_simple_division(huge(0.0),0.001,a_div_b,err)
print *, err%print()

contains

!> Simple division returning an integer flag (LAPACK style)
elemental subroutine very_simple_division(a,b,a_div_b,err)
real, intent(in) :: a,b
real, intent(out) :: a_div_b
type(state_type), optional, intent(out) :: err

type(state_type) :: err0
real, parameter :: MAXABS = huge(0.0)
character(*), parameter :: this = 'simple division'

!> Check a
if (b==0.0) then
! Division by zero
err0 = state_type(this,STDLIB_VALUE_ERROR,'Division by zero trying ',a,'/',b)
elseif (.not.abs(b)<MAXABS) then
! B is out of bounds
err0 = state_type(this,STDLIB_VALUE_ERROR,'B is infinity in a/b: ',[a,b]) ! use an array
elseif (.not.abs(a)<MAXABS) then
! A is out of bounds
err0 = state_type(this,STDLIB_VALUE_ERROR,'A is infinity in a/b: a=',a,' b=',b)
else
a_div_b = a/b
if (.not.abs(a_div_b)<MAXABS) then
! Result is out of bounds
err0 = state_type(this,STDLIB_VALUE_ERROR,'A/B is infinity in a/b: a=',a,' b=',b)
else
err0%state = STDLIB_SUCCESS
end if
end if

! Return error flag, or hard stop on failure
call err0%handle(err)

end subroutine very_simple_division


end program example_error_state2
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ set(fppFiles
stdlib_bitsets_large.fypp
stdlib_codata_type.fypp
stdlib_constants.fypp
stdlib_error.fypp
stdlib_hash_32bit.fypp
stdlib_hash_32bit_fnv.fypp
stdlib_hash_32bit_nm.fypp
Expand Down Expand Up @@ -102,7 +103,6 @@ set(SRC
stdlib_ansi_to_string.f90
stdlib_array.f90
stdlib_codata.f90
stdlib_error.f90
stdlib_hashmap_wrappers.f90
stdlib_hashmaps.f90
stdlib_hashmap_chaining.f90
Expand Down
84 changes: 0 additions & 84 deletions src/stdlib_error.f90

This file was deleted.

Loading
Loading