Skip to content

Commit

Permalink
add Query model capabilities
Browse files Browse the repository at this point in the history
  • Loading branch information
HLWeil committed May 9, 2022
1 parent a6470f1 commit ba81b27
Show file tree
Hide file tree
Showing 3 changed files with 284 additions and 54 deletions.
4 changes: 2 additions & 2 deletions src/ISADotnet/QueryModel/Assay.fs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ type QAssay(FileName : string option,MeasurementType : OntologyAnnotation option
static member getFinalOutputs (assay : QAssay) = QProcessSequence.getFinalOutputs assay

/// Returns the initial inputs final outputs of the assay, to which no processPoints
static member getRootInputOf (assay : QAssay) (sample : string) = QProcessSequence.getRootInputOf assay sample
static member getRootInputOf (assay : QAssay) (sample : string) = QProcessSequence.getRootInputsOfBy (fun _ -> true) sample assay

/// Returns the final outputs of the assay, which point to no further nodes
static member getFinalOutputsOf (assay : QAssay) (sample : string) = QProcessSequence.getFinalOutputsOf assay sample
static member getFinalOutputsOf (assay : QAssay) (sample : string) = QProcessSequence.getFinalOutputsOfBy (fun _ -> true) sample assay

static member toString (rwa : QAssay) = JsonSerializer.Serialize<QAssay>(rwa,JsonExtensions.options)

Expand Down
295 changes: 253 additions & 42 deletions src/ISADotnet/QueryModel/ProcessSequence.fs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,25 @@ type QProcessSequence (sheets : QSheet list) =
member this.Sheets = sheets

new (processSequence : Process list) =
let updateNodes (sheets : QSheet list) =
let mapping =
sheets
|> List.collect (fun s ->
s.Rows
|> List.collect (fun r -> [r.Input, r.InputType.Value; r.Output, r.OutputType.Value])
)
|> List.groupBy fst
|> List.map (fun (name,vs) -> name, vs |> List.map snd |> IOType.reduce)
|> Map.ofList
let updateRow row =
{row with
InputType = Some mapping.[row.Input]
OutputType = Some mapping.[row.Output]
}
sheets
|> List.map (fun sheet ->
{sheet with Rows = sheet.Rows |> List.map updateRow}
)
let sheets =
processSequence
|> List.groupBy (fun x ->
Expand All @@ -26,6 +45,7 @@ type QProcessSequence (sheets : QSheet list) =
x.Name.Value.Remove lastUnderScoreIndex
)
|> List.map (fun (name,processes) -> QSheet.fromProcesses name processes)
|> updateNodes
QProcessSequence(sheets)

static member fromAssay (assay : Assay) =
Expand Down Expand Up @@ -65,6 +85,57 @@ type QProcessSequence (sheets : QSheet list) =
interface IEnumerable with
member this.GetEnumerator() = (this :> IEnumerable<QSheet>).GetEnumerator() :> IEnumerator


static member getNodes (ps : #QProcessSequence) =
ps.Protocols
|> List.collect (fun p -> p.Rows |> List.collect (fun r -> [r.Input;r.Output]))
|> List.distinct

static member getSubTreeOf (node : string) (ps : #QProcessSequence) =
let rec collectForwardNodes nodes =
let newNodes =
ps.Sheets
|> List.collect (fun sheet ->
sheet.Rows
|> List.choose (fun r -> if List.contains r.Input nodes then Some r.Output else None)
)
|> List.append nodes
|> List.distinct

if newNodes = nodes then nodes
else collectForwardNodes newNodes

let collectBackwardNodes nodes =
let newNodes =
ps.Sheets
|> List.collect (fun sheet ->
sheet.Rows
|> List.choose (fun r -> if List.contains r.Output nodes then Some r.Input else None)
)
|> List.append nodes
|> List.distinct

if newNodes = nodes then nodes
else collectForwardNodes newNodes

let forwardNodes = collectForwardNodes [node]
let backwardNodes = collectBackwardNodes [node]

ps.Sheets
|> List.map (fun sheet ->
{sheet
with Rows =
sheet.Rows
|> List.filter (fun r ->
List.contains r.Input forwardNodes
|| (List.contains r.Output backwardNodes)

)

}
)
|> QProcessSequence

/// Returns the initial inputs final outputs of the assay, to which no processPoints
static member getRootInputs (ps : #QProcessSequence) =
let inputs = ps.Protocols |> List.collect (fun p -> p.Rows |> List.map (fun r -> r.Input))
Expand All @@ -79,29 +150,94 @@ type QProcessSequence (sheets : QSheet list) =
outputs
|> List.filter (fun i -> inputs.Contains i |> not)

/// Returns the initial inputs final outputs of the assay, to which no processPoints
static member getRootInputOf (ps : #QProcessSequence) (sample : string) =
static member getNodesBy (predicate : QueryModel.IOType -> bool) (ps : #QProcessSequence) =
ps.Protocols
|> List.collect (fun p ->
p.Rows
|> List.collect (fun r ->
[if predicate r.InputType.Value then r.Input; if predicate r.OutputType.Value then r.Output])
)
|> List.distinct

static member getRootInputsBy (predicate : QueryModel.IOType -> bool) (ps : #QProcessSequence) =
let mappings =
ps.Protocols
|> List.collect (fun p ->
p.Rows
|> List.map (fun r -> r.Output,r.Input)
|> List.map (fun r -> r.Input, r.Output)
|> List.distinct
)
|> List.groupBy fst
|> List.map (fun (out,ins) -> out, ins |> List.map snd)
|> Map.ofList
let rec loop lastState state =
if lastState = state then state

let typeMappings =
ps.Protocols
|> List.collect (fun p ->
p.Rows
|> List.collect (fun r -> [r.Input, r.InputType; r.Output, r.OutputType])
)
|> Map.ofList

let predicate (entity : string) =
match typeMappings.[entity] with
| Some t -> predicate t
| None -> false

let rec loop (searchEntities : string list) (foundEntities : string list) =
if searchEntities.IsEmpty then foundEntities |> List.distinct
else
let newState =
state
|> List.collect (fun s ->
mappings.TryFind s
|> Option.defaultValue [s]
)
loop state newState
loop [] [sample]
let targs = searchEntities |> List.filter predicate
let nonTargs = searchEntities |> List.filter (predicate >> not)
let nextSearchEntities = nonTargs |> List.collect (fun en -> Map.tryFind en mappings |> Option.defaultValue [])
loop nextSearchEntities targs

loop (QProcessSequence.getRootInputs ps) []

static member getFinalOutputsBy (predicate : QueryModel.IOType -> bool) (ps : #QProcessSequence) =
let mappings =
ps.Protocols
|> List.collect (fun p ->
p.Rows
|> List.map (fun r -> r.Output, r.Input )
|> List.distinct
)
|> List.groupBy fst
|> List.map (fun (out,ins) -> out, ins |> List.map snd)
|> Map.ofList

let typeMappings =
ps.Protocols
|> List.collect (fun p ->
p.Rows
|> List.collect (fun r -> [r.Input, r.InputType; r.Output, r.OutputType])
)
|> Map.ofList

let predicate (entity : string) =
match typeMappings.[entity] with
| Some t -> predicate t
| None -> false

let rec loop (searchEntities : string list) (foundEntities : string list) =
if searchEntities.IsEmpty then foundEntities |> List.distinct
else
let targs = searchEntities |> List.filter predicate
let nonTargs = searchEntities |> List.filter (predicate >> not)
let nextSearchEntities = nonTargs |> List.collect (fun en -> Map.tryFind en mappings |> Option.defaultValue [])
loop nextSearchEntities targs

loop (QProcessSequence.getFinalOutputs ps) []

/// Returns the initial inputs final outputs of the assay, to which no processPoints
static member getRootInputsOfBy (predicate : QueryModel.IOType -> bool) (sample : string) (ps : #QProcessSequence) =
QProcessSequence.getSubTreeOf sample ps
|> QProcessSequence.getRootInputsBy predicate

/// Returns the final outputs of the assay, which point to no further nodes
static member getFinalOutputsOfBy (predicate : QueryModel.IOType -> bool) (sample : string) (ps : #QProcessSequence) =
QProcessSequence.getSubTreeOf sample ps
|> QProcessSequence.getFinalOutputsBy predicate

/// Returns the initial inputs final outputs of the assay, to which no processPoints
static member getPreviousValuesOf (ps : #QProcessSequence) (sample : string) =
Expand Down Expand Up @@ -157,29 +293,6 @@ type QProcessSequence (sheets : QSheet list) =
loop [] [] [sample]
|> ValueCollection

/// Returns the final outputs of the assay, which point to no further nodes
static member getFinalOutputsOf (ps : #QProcessSequence) (sample : string) =
let mappings =
ps.Protocols
|> List.collect (fun p ->
p.Rows
|> List.map (fun r -> r.Input,r.Output)
|> List.distinct
)
|> List.groupBy fst
|> List.map (fun (inp,outs) -> inp, outs |> List.map snd)
|> Map.ofList
let rec loop lastState state =
if lastState = state then state
else
let newState =
state
|> List.collect (fun s ->
mappings.TryFind s
|> Option.defaultValue [s]
)
loop state newState
loop [] [sample]

member this.Nearest =
this.Sheets
Expand All @@ -191,8 +304,9 @@ type QProcessSequence (sheets : QSheet list) =
|> List.collect (fun sheet ->
sheet.Rows
|> List.collect (fun r ->
r.Input
|> QProcessSequence.getRootInputOf this |> List.distinct

QProcessSequence.getRootInputsOfBy (fun _ -> true) r.Input this
|> List.distinct
|> List.collect (fun inp ->
r.Values
|> List.map (fun v ->
Expand All @@ -208,8 +322,9 @@ type QProcessSequence (sheets : QSheet list) =
|> List.collect (fun sheet ->
sheet.Rows
|> List.collect (fun r ->
r.Output
|> QProcessSequence.getFinalOutputsOf this |> List.distinct

QProcessSequence.getFinalOutputsOfBy (fun _ -> true) r.Output this
|> List.distinct
|> List.collect (fun out ->
r.Values
|> List.map (fun v ->
Expand All @@ -225,8 +340,8 @@ type QProcessSequence (sheets : QSheet list) =
|> List.collect (fun sheet ->
sheet.Rows
|> List.collect (fun r ->
let outs = r.Output |> QProcessSequence.getFinalOutputsOf this |> List.distinct
let inps = r.Input |> QProcessSequence.getRootInputOf this |> List.distinct
let outs = QProcessSequence.getFinalOutputsOfBy (fun _ -> true) r.Output this |> List.distinct
let inps = QProcessSequence.getRootInputsOfBy (fun _ -> true) r.Input this |> List.distinct
outs
|> List.collect (fun out ->
inps
Expand All @@ -241,6 +356,84 @@ type QProcessSequence (sheets : QSheet list) =
)
|> IOValueCollection

member this.Nodes() =
QProcessSequence.getNodes(this)

member this.FirstNodes() =
QProcessSequence.getRootInputs(this)

member this.LastNodes() =
QProcessSequence.getFinalOutputs(this)

member this.FirstNodesOf(node) =
QProcessSequence.getRootInputsOfBy (fun _ -> true) node this

member this.LastNodesOf(node) =
QProcessSequence.getFinalOutputsOfBy (fun _ -> true) node this

member this.Samples() =
QProcessSequence.getNodesBy (fun (io : IOType) -> io.isSample) this

member this.FirstSamples() =
QProcessSequence.getRootInputsBy (fun (io : IOType) -> io.isSample) this

member this.LastSamples() =
QProcessSequence.getFinalOutputsBy (fun (io : IOType) -> io.isSample) this

member this.FirstSamplesOf(node) =
QProcessSequence.getRootInputsOfBy (fun (io : IOType) -> io.isSample) node this

member this.LastSamplesOf(node) =
QProcessSequence.getFinalOutputsOfBy (fun (io : IOType) -> io.isSample) node this

member this.Sources() =
QProcessSequence.getNodesBy (fun (io : IOType) -> io.isSource) this

member this.Data() =
QProcessSequence.getNodesBy (fun (io : IOType) -> io.isData) this

member this.FirstData() =
QProcessSequence.getRootInputsBy (fun (io : IOType) -> io.isData) this

member this.LastData() =
QProcessSequence.getFinalOutputsBy (fun (io : IOType) -> io.isData) this

member this.FirstDataOf(node) =
QProcessSequence.getRootInputsOfBy (fun (io : IOType) -> io.isData) node this

member this.LastDataOf(node) =
QProcessSequence.getFinalOutputsOfBy (fun (io : IOType) -> io.isData) node this

member this.RawData() =
QProcessSequence.getNodesBy (fun (io : IOType) -> io.isRawData) this

member this.FirstRawData() =
QProcessSequence.getRootInputsBy (fun (io : IOType) -> io.isRawData) this

member this.LastRawData() =
QProcessSequence.getFinalOutputsBy (fun (io : IOType) -> io.isRawData) this

member this.FirstRawDataOf(node) =
QProcessSequence.getRootInputsOfBy (fun (io : IOType) -> io.isRawData) node this

member this.LastRawDataOf(node) =
QProcessSequence.getFinalOutputsOfBy (fun (io : IOType) -> io.isRawData) node this

member this.ProcessedData() =
QProcessSequence.getNodesBy (fun (io : IOType) -> io.isProcessedData) this

member this.FirstProcessedData() =
QProcessSequence.getRootInputsBy (fun (io : IOType) -> io.isProcessedData) this

member this.LastProcessedData() =
QProcessSequence.getFinalOutputsBy (fun (io : IOType) -> io.isProcessedData) this

member this.FirstProcessedDataOf(node) =
QProcessSequence.getRootInputsOfBy (fun (io : IOType) -> io.isProcessedData) node this

member this.LastProcessedDataOf(node) =
QProcessSequence.getFinalOutputsOfBy (fun (io : IOType) -> io.isProcessedData) node this

member this.ValuesOf(name) =
(QProcessSequence.getPreviousValuesOf this name).Values @ (QProcessSequence.getSucceedingValuesOf this name).Values
|> ValueCollection
Expand All @@ -260,6 +453,24 @@ type QProcessSequence (sheets : QSheet list) =
member this.SucceedingCharacteristicsOf(name) =
this.SucceedingValuesOf(name).Characteristics

member this.ParametersOf(name) =
this.ValuesOf(name).Parameters

member this.PreviousParametersOf(name) =
this.PreviousValuesOf(name).Parameters

member this.SucceedingParametersOf(name) =
this.SucceedingValuesOf(name).Parameters

member this.FactorsOf(name) =
this.ValuesOf(name).Factors

member this.PreviousFactorsOf(name) =
this.PreviousValuesOf(name).Factors

member this.SucceedingFactorsOf(name) =
this.SucceedingValuesOf(name).Factors

//static member toString (rwa : QAssay) = JsonSerializer.Serialize<QAssay>(rwa,JsonExtensions.options)

//static member toFile (path : string) (rwa:QAssay) =
Expand Down
Loading

0 comments on commit ba81b27

Please sign in to comment.