---
title: "Using FormalContexts and ConceptLattices"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Using FormalContexts and ConceptLattices}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7,
  fig.height = 5,
  warning = FALSE
)
```

# Introduction

In this vignette, we present the main functionalities and data structures of the `fcaR` package when working with formal contexts and concepts, in FCA.

We load the `fcaR` package by:
```{r setup}
library(fcaR)
```

# Datasets

We are going to work with two datasets, a crisp one and a fuzzy one.

The classical (binary) dataset is the well-known `planets` formal context, presented in 

> Wille R (1982). “Restructuring Lattice Theory: An Approach Based on Hierarchies of Concepts.” In Ordered Sets, pp. 445–470. Springer.

```{r}
knitr::kable(planets, format = "html", booktabs = TRUE)
```

The other formal context is fuzzy and is defined by the following matrix I:
```{r echo = FALSE}
objects <- paste0("O", 1:6)
n_objects <- length(objects)

attributes <- paste0("P", 1:6)
n_attributes <- length(attributes)

I <- matrix(
  data = c(
    0, 1, 0.5, 0, 0, 0.5,
    0, 1, 0.5, 0, 0, 0.5,
    0.5, 1, 0, 0, 1, 0,
    0.5, 0, 0, 1, 0.5, 0,
    1, 0, 0, 0.5, 0, 0,
    0, 0, 1, 0, 0, 1
  ),
  nrow = n_objects,
  byrow = FALSE
)

colnames(I) <- attributes
rownames(I) <- objects
```

```{r}
knitr::kable(I, format = "html", booktabs = TRUE)
```

# Working with Formal Contexts

The first step when using the `fcaR` package to analyze a formal context is to create an object of class `FormalContext` which will store all the information related to the context.

In our examples, we create two objects:
```{r}
fc_planets <- FormalContext$new(planets)
fc_I <- FormalContext$new(I)
```

Internally, the object stores information about whether the context is binary or the names of objects and attributes, which are taken from the rownames and colnames of the provided matrix.


## Plotting, printing and latex-ing the FormalContext

Once created the `FormalContext` objects, we can print them or plot them as heatmaps (with functions `print()` and `plot()`):
```{r}
print(fc_planets)
print(fc_I)
```

```{r fig.dim=c(4,4)}
fc_planets$plot()
fc_I$plot()
```

Also, we can export the formal context as a LaTeX table:
```{r}
fc_planets$to_latex()
```
## Importing a Formal Context from File

One can also create `FormalContext`s by importing RDS, CSV or CXT files directly:
```{r}
# Read CSV
filename <- system.file("contexts", "airlines.csv",
  package = "fcaR"
)

fc1 <- FormalContext$new(filename)
fc1

# Read CXT
filename <- system.file("contexts", "lives_in_water.cxt",
  package = "fcaR"
)

fc2 <- FormalContext$new(filename)
fc2
```

## Dual Formal Context

We can compute the dual formal context of a given one by using the `dual()` method:

```{r}
fc_dual <- fc_planets$dual()
fc_dual
```

The result is a `FormalContext` where attributes are now the objects of the previous formal context and viceversa.

## Closures

The basic operation in FCA is the computation of closures given an attribute set, by using the two derivation operators, extent and intent.

The intent of a (probably fuzzy) set of objects is the set of their common attributes:
```{r}
# Define a set of objects
S <- Set$new(attributes = fc_planets$objects)
S$assign(Earth = 1, Mars = 1)
S

# Compute the intent of S
fc_planets$intent(S)
```

Analogously, the extent of a set of attributes is the set of objects which possess all the attributes in the given set:
```{r}
# Define a set of objects
S <- Set$new(attributes = fc_planets$attributes)
S$assign(moon = 1, large = 1)
S

# Compute the extent of S
fc_planets$extent(S)
```

The composition of intent and extent is the closure of a set of attributes:
```{r}
# Compute the closure of S
Sc <- fc_planets$closure(S)
Sc
```

This means that all planets which have the attributes `moon` and `large` also have `far` in common.

We can check whether a set is closed (that is, it is equal to its closure), using `is_closed()`:
```{r}
fc_planets$is_closed(S)
fc_planets$is_closed(Sc)
```



## Clarification and Reduction

An interesting point when managing formal contexts is the ability to reduce the context, removing redundancies, while retaining all the knowledge. This is accomplished by two functions: `clarify()`, which removes duplicated attributes and objects (columns and rows in the original matrix); and `reduce()`, which uses closures to remove dependent attributes, but only on binary formal contexts. The resulting `FormalContext` is equivalent to the original one in both cases.

```{r}
fc_planets$reduce(TRUE)

fc_I$clarify(TRUE)
```

Note that merged attributes or objects are stored in the new formal context by using squared brackets to unify them, e.g. `[Mercury, Venus]`.

## Extracting Implications and Concepts

The function to extract the canonical basis of implications and the concept lattice is `find_implications()`. Its use is to store a `ConceptLattice` and an `ImplicationSet` objects internally in the `FormalContext` object after running the NextClosure algorithm.

It can be used both for binary and fuzzy formal contexts, resulting in binary or fuzzy concepts and implications:
```{r}
fc_planets$find_implications()

fc_I$find_implications()
```

We can inspect the results as:
```{r}
# Concepts
fc_planets$concepts

# Implications
fc_planets$implications
```


## Protoconcepts

In addition to concepts, one can compute *protoconcepts*. A protoconcept is a pair $(A, B)$ of object and attribute sets such that $A' = B''$. This definition generalizes concepts (where $A' = B$ and $B' = A$, which implies $A' = B''$) and is useful in certain applications.

To find all protoconcepts, use `find_protoconcepts()`:
```{r}
P <- fc_planets$find_protoconcepts()
length(P)
```
The result is a list of pairs (extent, intent). Each element of the list matches a concept or a protoconcept.


## Standard Context

Once we have computed the concepts, we can build the _standard context_ (J, M, $\le$), where J is the set of join-irreducible concepts and M are the meet-irreducible ones. Join and meet are another name for supremum and infimum operations in the concept lattice.

The function `standardize()` works for all FormalContext where the concept lattice has been found, and it produces a new `FormalContext` object:
```{r}
fc_planets$standardize()
fc_I$standardize()
```

Note that now objects are named J1, J2... and attributes are M1, M2..., from join and meet.

## Saving and loading

A `FormalContext` is saved in RDS format using its own `save()` method, which is more efficient than the base `saveRDS()` and `readRDS()`.

```{r eval = FALSE}
fc$save(filename = "./fc.rds")
```

In order to load a previously saved `FormalContext`, it suffices to do:
```{r eval = FALSE}
fc2 <- FormalContext$new("./fc.rds")
```

In this case, `fc` and `fc2` contain the same information.

# Concept Lattice

We are going to use the previously computed concept lattices for the two `FormalContext` objects.

## Plot, print and LaTeX

The concept lattice can be plotted using a Hasse diagram and the function `plot()` inside the `ConceptLattice` component:
```{r}
fc_planets$concepts$plot()
fc_I$concepts$plot()
```

If one desires to get the list of concepts printed, or in LaTeX format, just:
```{r}
# Printing
fc_planets$concepts

# LaTeX
fc_planets$concepts$to_latex()
```


## Getting all extents, intents and retrieving concepts

For a `ConceptLattice`, one may want to retrieve particular concepts, using a subsetting as in `R`:
```{r}
fc_planets$concepts[2:3]
```

Or get all the extents and all the intents of all concepts, as sparse matrices:
```{r eval = FALSE}
fc_planets$concepts$extents()
fc_planets$concepts$intents()
```

## Concept support
The support of concepts can be computed using the function `support()`:
```{r}
fc_planets$concepts$support()
```

## Sublattices

When the concept lattice is too large, it can be useful in certain occasions to just work with a sublattice of the complete lattice. To this end, we use the `sublattice()` function.

For instance, to build the sublattice of those concepts with support greater than 0.5, we can do:
```{r}
# Get the index of those concepts with support
# greater than the threshold
idx <- which(fc_I$concepts$support() > 0.2)
# Build the sublattice
sublattice <- fc_I$concepts$sublattice(idx)
sublattice
```

And we can plot just the sublattice:
```{r}
sublattice$plot()
```

## Subconcepts, superconcepts, infimum and supremum

It may be interesting to use the notions of subconcept and superconcept. Given a concept, we can compute all its subconcepts and all its superconcepts:
```{r}
# The fifth concept
C <- fc_planets$concepts$sub(5)
C
# Its subconcepts:
fc_planets$concepts$subconcepts(C)
# And its superconcepts:
fc_planets$concepts$superconcepts(C)
```

Also, we can define infimum and supremum of a set of concepts as the greatest common subconcept of all the given concepts, and the lowest common superconcept of them, and can be computed by:
```{r}
# A list of concepts
C <- fc_planets$concepts[5:7]
C

# Supremum of the concepts in C
fc_planets$concepts$supremum(C)
# Infimum of the concepts in C
fc_planets$concepts$infimum(C)
```

## Join- and meet- irreducible elements

Also irreducible elements with respect to join (supremum) and meet (infimum) can be computed for a given concept lattice:
```{r}
fc_planets$concepts$join_irreducibles()
fc_planets$concepts$meet_irreducibles()
```

This are the concepts used to build the _standard context_, mentioned above.

