Packages
Toolkit for acquisition target screening: thesis briefs, a weighted composite that zeroes out group-owned targets, ranking and signal coverage.
Current section
Files
Jump to
Current section
Files
acquisitionuniverse
README.md
README.md
# acquisitionuniverse for Elixir
Elixir functions for people who work through acquisition target lists. Rank companies, validate a thesis brief, print it as text and count which of the 15 common signals are actually visible. Plain maps in, plain maps out, no dependencies.
```elixir
{:acquisitionuniverse, "~> 1.0"}
```
## Rank
```elixir
companies = [
%{id: "A", mandate_fit: 90, outreach_suitability: 80, transition_context: 50},
%{id: "B", mandate_fit: 96, outreach_suitability: 90, transition_context: 70, group_owned: true}
]
AcquisitionUniverse.rank(companies) |> Enum.map(&{&1.id, &1.composite})
# [{"A", 84.0}, {"B", 74.2}]
```
B is the stronger fit. It is owned by a group, so it carries no outreach points and A comes first. Provide your own weights as a map with `:mandate_fit`, `:outreach_suitability` and `:transition_context`.
## Brief
```elixir
brief = %{
name: "Precision machining, Carolinas",
vertical: "Precision machining",
regions: ["North Carolina", "South Carolina"],
employees_min: 10,
employees_max: 90,
exclusions: ["group-owned"]
}
[] = AcquisitionUniverse.validate_brief(brief)
IO.puts(AcquisitionUniverse.brief_text(brief))
```
## Coverage
```elixir
[s0, _, s2 | _] = AcquisitionUniverse.signals()
AcquisitionUniverse.signal_coverage(%{s0 => "family associated", s2 => nil})
# %{visible: 1, checked: 2, ratio: 0.5}
```
## Functions
| Function | Result |
|---|---|
| `signals/0` | list of 15 names |
| `default_weights/0` | 0.7, 0.2, 0.1 |
| `composite/2` | float, 0 to 100 |
| `rank/2` | maps with `:composite`, best first |
| `signal_coverage/1` | map with visible, checked, ratio |
| `validate_brief/1` | list of problems |
| `brief_text/1` | string |
| `pilot_url/0` | pilot request page |
## LiveView idea
A LiveView with a form for the weights and a table for `rank/2` lets a partner drag the balance between fit and suitability and watch the list reorder. The data is just a list of maps, so `Phoenix.LiveView.stream/3` fits well.
## Process a CSV
```elixir
rows =
"screen.csv"
|> File.stream!()
|> Stream.drop(1)
|> Stream.map(&String.split(String.trim(&1), ","))
|> Enum.map(fn [id, fit, out, trans, owned] ->
%{id: id, mandate_fit: String.to_float(fit), outreach_suitability: String.to_float(out),
transition_context: String.to_float(trans), group_owned: owned == "yes"}
end)
AcquisitionUniverse.rank(rows) |> Enum.take(10)
```
## Related reading
Add-on buyers can compare notes in the [portfolio company BD](https://www.acquisitionuniverse.com/for/portfolio-company-bd.php) guide. The same team publishes [cookieless audience database](https://www.cookielessaudiences.com/industries/curation-platforms.php) material for curation platforms and a [skill normalization](https://www.resumereaderapi.com/normalization/skills-examples.php) reference for resume data.
## Questions
**Does it call a server?** No.
**Elixir version?** 1.14 or later.
**License?** MIT. info@alpha-quantum.com