///|
/// Analyst pipeline: categorical incidence -> closed patterns -> generators -> exact dependencies.
fn feature_pipeline() -> Json raise @fca.FcaError {
  let data = @fca.parse_csv(
    "object,touch,portable,radio,keyboard\nphone,1,1,1,0\ntablet,1,1,0,0\nwatch,1,1,1,0\ndesktop,0,0,0,1\nlaptop,0,1,1,1\nworkstation,0,0,1,1\n",
  )
  let patterns = data.frequent_concepts(0.5)
  let target = data.closure([data.attribute_index("touch").unwrap()])
  let generators = data.minimal_generators(target)
  let basis = data.canonical_basis()
  Json::object({
    "workflow": Json::string("feature-analysis"),
    "objects": Json::number(data.object_count().to_double()),
    "frequent_patterns": Json::number(patterns.length().to_double()),
    "touch_closure": Json::array(
      data.attribute_labels(target).map(fn(s) { Json::string(s) }),
    ),
    "minimal_generators": Json::array(
      generators.map(generator => {
        Json::array(
          data.attribute_labels(generator).map(fn(s) { Json::string(s) }),
        )
      }),
    ),
    "exact_basis": basis.to_json(),
    "catalog": data.concept_report(),
  })
}

///|
fn main {
  let report = feature_pipeline() catch {
    _ => abort("feature pipeline failed")
  }
  println(report.stringify())
}