Git Product home page Git Product logo

renaissance-ada's Introduction

Renaissance-Ada

The Renaissance-Ada project develops tooling for analysis and manipulation of Ada software. The Renaissance-Ada project builds on top of LibAdalang and includes the following functionality

Examples

The image below shows the dependencies of Find-related subprograms of the Rejuvenation Library as extracted by the Dependency Graph Extractor and queried using Neo4J. Dependencies of Find-related subprograms of the Rejuvenation Library

Snippets from diff made with Code Reviewer

   function Release_Only (Mode : Operation_Mode) return Boolean is
-     (case Mode is when Release_Size_Mode | Release_Speed_Mode => True, when others => False);
+     (Mode in Release_Size_Mode | Release_Speed_Mode);
- if Valid then
-    Add (Value, 0, 0, 0);
- else
-    Add ("", 0, 0, 0);
- end if;
+ Add ((if Valid then Value else ""), 0, 0, 0);
- for Acf of Acfs loop
-    if Acf = null then
-       return False;
-    end if;
- end loop;
- return True;
+ return (for all Acf of Acfs => Acf /= null);

Example based on aws code

-   Max_Overhead : Stream_Element_Count range 0 .. 2**15 := 81 with Atomic;
-   for Max_Overhead'Size use 16;
+   Max_Overhead : Stream_Element_Count range 0 .. 2**15 := 81 with
+      Atomic,
+      Size => 16;

Used by Industry

Nexperia described during the AdaCore Tech Days how they benefit from the Renaissance-Ada tooling.

Renaissance History

The Renaissance approach to legacy software was initially developed by ESI in public-private research projects together with Thermo Fisher and Philips.

Enhance insight and reduce complexity

The Renaissance approach is an interative process of two steps that strengthen each other

  • enhance insight by analysis and
  • reduce complexity by manipulation.

For more info, see e.g. this Bits & Chips article and ESI's research on model-based software transformation or listen to Tom van de Ven interviewing Pierre van de Laar on Renaissance-Ada

The development of Renaissance tooling to target Ada software started in Bright, a public-private research project together with ITEC, an independent subsidiary of Nexperia.

Clone archive

Use

git clone --recurse-submodules https://github.com/TNO/Renaissance-Ada.git

Related technologies

  • HayStack-Ada is a GNATStudio plug-in for AST-based Find and Replace. HayStack-Ada uses a re-implementation of the rejuvenation library in python.
  • OpenRewrite is a semantic code search and transformation ecosystem for Java and other source code.
  • Rascal MPL is a metaprogramming language that integrates source code analysis, transformation, and generation primitives on the language level. The Ada-Air project aims to add support for Ada to Rascal MPL.
  • Spoofax is a language designer's workbench. Spoofax supports concrete syntax to specify code transformations. Unfortunately, Spoofax still lacks support for Ada.

renaissance-ada's People

Contributors

pjljvandelaar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

renaissance-ada's Issues

Improve pattern matching

The current implementation of match pattern fails in some cases.
This is however not needed.

($M_X, $M_X) fails on (1,2,3,1,2,3)

($M_X, 1,1, $M_Y) fails on (1,2,1,1,3,4)

($M_X, $S_Y, $S_Z) fails on (1,2,3)

Note we should not backtrack with
($M_Args) on (1,2,3,4,5,6), just match on length: $M_Args has length of 6!

Note: ($M_X, 1,1, $M_Y) on (1,1,2,1,1,3,4) has 2 solutions:
not only pattern but also instance determines number of matches

Solution

  • Known lengths
    • actual ASTnodes
    • single place holders
    • already known/decided multiplaceholders
  • Bag of unknown multi placeholders [match with list instance]
    • Only one multi placeholders: length can be determined (length instance - sum of known length) / occurrence of multi placeholder
    • Pick a multi placeholder: iterate length from 0 to (length instance - sum of known length) / occurrence of multi

Point of attention (ignore patterns - present in C++ version)

Add Has_Side_Effect function for place holders

We need a function to determine whether a place holder (which points to an expression)
has a side effect.

We can start with a simple version that
states that a function call always has a side effect,
reading constants and variable has not side effect,
and operators have a side effect when one of there arguments has a side effect.

Introduce own Pattern kind

Patterns currently reuse LibAdaLang's parse rules.
However, we only need 3 or 4 kinds

  • Expression
  • List of Statements
  • List of Declarations
  • Package

Could we simplify the interface of Pattern and even more hide the dependency on libadalang?

Moving away from introducing any issue - extra functionality needed?

Since human resource are typically scarce within organizations,
we are preferring only to change when we are absolutely certain that no compiler error or warning is introduced.

Consequently, our users might not be exposed to some rewrites that would otherwise educate them on particular Ada constructions.

Furthermore, some changes are not done since we lack the possibility to do post processing.
For example, replacing

  if X.Length > 0 then ...

by

  if not X.Is_Empty then ...

can introduce a compiler warning when this was the only location where operators on Count_Type where used,
and thus the with/use clause becomes obsolete.

Instead of prevent these rewrites should we add some post processing capabilities, e.g. on the changed file,
to ensure it still compiles without warnings?

AST pattern matching, yet equal based on text

We should make Match pattern really AST based [even when it becomes somewhat slower].

In Renaissance-C++ the change was:

	@Override
	protected boolean areEqualAsText(IASTNode node1, IASTNode node2) {
-		return node1.getRawSignature().equals(node2.getRawSignature());
+		String[] tokens1 = LexerCdt.getTokens(node1.getRawSignature());
+		String[] tokens2 = LexerCdt.getTokens(node2.getRawSignature());
+		if (tokens1.length != tokens2.length) {
+			return false;
+		}
+		for (int i = 0; i < tokens1.length; i++) {
+			if (!tokens1[i].equals(tokens2[i])) {
+				return false;
+			}
+		}
+		return true;
	}

Add fixed point rewriters

The rewriters library current lacks a relevant class of rewriters: fixed point rewriters.
These rewriters apply a rewrite until the code no longer changes.

These rewriters are relevant for rewrites like

Rewriter_Combine_In_Range_And_Equal :

where the replacement of pattern $S_Var in $M_Vals or else $S_Var = $S_Val by $S_Var in $M_Vals | $S_Val
can be applied multiple times in succession on instances like
X in [1..3] or else X = 5 or else X = 7 or else X = 9

Handle lists of complex AST nodes

For many find and replacements, we need to support lists of complex AST nodes.

For example to rewrite a function to a function expression, we need to specify the list of parameters.

Function to determine whether execution of place holder has effect on another place holder

We need a function to determine whether execution of a place holder has effect on another place holder.

We need this for rewrite rules like

Rewriter_Concat_Before_If_Expression :

where
(if $S_Cond then $S_Expr & $S_True else $S_Expr & $S_False)
can only be replaced by
($S_Expr & (if $S_Cond then $S_True else $S_False))
when the execution of $S_Cond doesn't change the value of $S_Expr and vice versa.

Replace using Type of Placeholder

We have found some case, like Max, Min and X - X, where the replacement needs the type
like Integer'Max, Float'Min and Float(0).

How can we prevent that we have the same patterns for all (basic) types?

Should we support a special placeholder, e.g. $T_X in replace patterns to insert the type of the single place holder $S_X?

Enhanced functionality: advanced nesting of rewriters

Our current rewrite lib has some limitations.

For example, currently we don't support the following rewrite

use element instead of index when index is only used to access elements

To be more precise:
Replace
for $S_I in $S_A'Range loop $M_Stmts; end loop;
when
$M_Stmts; only uses $S_I in $S_A ($S_I)
by
for Element of $S_A loop <$M_Stmts;> end loop;
where
<$M_Stmts;> is obtained by replacing $S_A ($S_I) by Element in $M_Stmts;

Can we come up with an interface that is clear for our users
and enables them to perform these kind of nested rewrites?

Analyse aggregate projects

The rejuvenation library currently can't handle aggregate projects.

I propose to allow aggregate projects by use accumulating the analysis units of their individual projects .

Split rewriters library

The rewriter library now contains two kind of code

  1. Code to combine, repeat, and chain rewrites
  2. List of general Ada rewrites

I propose to split them!

Improve project structure

Currently we have to problems in our project structure:

  1. Renaissance_Ada.gpr:1:19: cannot aggregate abstract project "Standard_Options"
  2. Multiple test projects with the same name.
    Same name for all test projects is enforced by GNATtest for nice IDE integration, yet aggregate project wants unique project names - issue known to AdaCore

How to solve this?

Improvement to Inheritance structure needed

When running the cyper query

MATCH 
    (user:AdaDeclaration)-[:References]->(provider:AdaDeclaration),
    (user)-[:Source]->(file:File),
    (provider)-[:Source]->(adsFile:AdaSpecificationFile)
WHERE
    adsFile.name ENDS WITH "rejuvenation.ads"
RETURN file, count(user) ORDER BY count(user) DESC

on the current graphml file from rejuvenation library (obtained with Dependency_Graph_Extractor)
one gets

╒══════════════════════════════════════════════════════════════════════╤═════════════╕
│"file"                                                                │"count(user)"│
╞══════════════════════════════════════════════════════════════════════╪═════════════╡
│{"relativeName":"rejuvenation-finder.adb","subtype":"AdaBodyFile","nam│12           │
│e":"file:src\rejuvenation-finder.adb","type":"File","fullyQualifiedNam│             │
│e":"src\rejuvenation-finder.adb"}                                     │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-finder.ads","subtype":"AdaSpecificationF│10           │
│ile","name":"file:src\rejuvenation-finder.ads","type":"File","fullyQua│             │
│lifiedName":"src\rejuvenation-finder.ads"}                            │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-replacer.adb","subtype":"AdaBodyFile","n│8            │
│ame":"file:src\rejuvenation-replacer.adb","fullyQualifiedName":"src\re│             │
│juvenation-replacer.adb","type":"File"}                               │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-match_patterns.ads","subtype":"AdaSpecif│8            │
│icationFile","name":"file:src\rejuvenation-match_patterns.ads","fullyQ│             │
│ualifiedName":"src\rejuvenation-match_patterns.ads","type":"File"}    │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-utils.adb","subtype":"AdaBodyFile","name│7            │
│":"file:src\rejuvenation-utils.adb","type":"File","fullyQualifiedName"│             │
│:"src\rejuvenation-utils.adb"}                                        │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-match_patterns.adb","subtype":"AdaBodyFi│7            │
│le","name":"file:src\rejuvenation-match_patterns.adb","fullyQualifiedN│             │
│ame":"src\rejuvenation-match_patterns.adb","type":"File"}             │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-utils.ads","subtype":"AdaSpecificationFi│7            │
│le","name":"file:src\rejuvenation-utils.ads","type":"File","fullyQuali│             │
│fiedName":"src\rejuvenation-utils.ads"}                               │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-find_and_replacer.adb","subtype":"AdaBod│4            │
│yFile","name":"file:src\rejuvenation-find_and_replacer.adb","fullyQual│             │
│ifiedName":"src\rejuvenation-find_and_replacer.adb","type":"File"}    │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-placeholders.ads","subtype":"AdaSpecific│2            │
│ationFile","name":"file:src\rejuvenation-placeholders.ads","fullyQuali│             │
│fiedName":"src\rejuvenation-placeholders.ads","type":"File"}          │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-placeholders.adb","subtype":"AdaBodyFile│2            │
│","name":"file:src\rejuvenation-placeholders.adb","fullyQualifiedName"│             │
│:"src\rejuvenation-placeholders.adb","type":"File"}                   │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-find_and_replacer.ads","subtype":"AdaSpe│1            │
│cificationFile","name":"file:src\rejuvenation-find_and_replacer.ads","│             │
│fullyQualifiedName":"src\rejuvenation-find_and_replacer.ads","type":"F│             │
│ile"}                                                                 │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-factory.adb","subtype":"AdaBodyFile","na│1            │
│me":"file:src\rejuvenation-factory.adb","fullyQualifiedName":"src\reju│             │
│venation-factory.adb","type":"File"}                                  │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-parameters.ads","subtype":"AdaSpecificat│1            │
│ionFile","name":"file:src\rejuvenation-parameters.ads","fullyQualified│             │
│Name":"src\rejuvenation-parameters.ads","type":"File"}                │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-navigation.ads","subtype":"AdaSpecificat│1            │
│ionFile","name":"file:src\rejuvenation-navigation.ads","fullyQualified│             │
│Name":"src\rejuvenation-navigation.ads","type":"File"}                │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-patterns.adb","subtype":"AdaBodyFile","n│1            │
│ame":"file:src\rejuvenation-patterns.adb","fullyQualifiedName":"src\re│             │
│juvenation-patterns.adb","type":"File"}                               │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-factory.ads","subtype":"AdaSpecification│1            │
│File","name":"file:src\rejuvenation-factory.ads","fullyQualifiedName":│             │
│"src\rejuvenation-factory.ads","type":"File"}                         │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-printer.ads","subtype":"AdaSpecification│1            │
│File","name":"file:src\rejuvenation-printer.ads","fullyQualifiedName":│             │
│"src\rejuvenation-printer.ads","type":"File"}                         │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-node_locations.ads","subtype":"AdaSpecif│1            │
│icationFile","name":"file:src\rejuvenation-node_locations.ads","fullyQ│             │
│ualifiedName":"src\rejuvenation-node_locations.ads","type":"File"}    │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-file_utils.ads","subtype":"AdaSpecificat│1            │
│ionFile","name":"file:src\rejuvenation-file_utils.ads","fullyQualified│             │
│Name":"src\rejuvenation-file_utils.ads","type":"File"}                │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-navigation.adb","subtype":"AdaBodyFile",│1            │
│"name":"file:src\rejuvenation-navigation.adb","fullyQualifiedName":"sr│             │
│c\rejuvenation-navigation.adb","type":"File"}                         │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-replacer.ads","subtype":"AdaSpecificatio│1            │
│nFile","name":"file:src\rejuvenation-replacer.ads","fullyQualifiedName│             │
│":"src\rejuvenation-replacer.ads","type":"File"}                      │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-pretty_print.adb","subtype":"AdaBodyFile│1            │
│","name":"file:src\rejuvenation-pretty_print.adb","fullyQualifiedName"│             │
│:"src\rejuvenation-pretty_print.adb","type":"File"}                   │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-string_utils.adb","subtype":"AdaBodyFile│1            │
│","name":"file:src\rejuvenation-string_utils.adb","fullyQualifiedName"│             │
│:"src\rejuvenation-string_utils.adb","type":"File"}                   │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-indentation.ads","subtype":"AdaSpecifica│1            │
│tionFile","name":"file:src\rejuvenation-indentation.ads","fullyQualifi│             │
│edName":"src\rejuvenation-indentation.ads","type":"File"}             │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-printer.adb","subtype":"AdaBodyFile","na│1            │
│me":"file:src\rejuvenation-printer.adb","fullyQualifiedName":"src\reju│             │
│venation-printer.adb","type":"File"}                                  │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-simple_factory.adb","subtype":"AdaBodyFi│1            │
│le","name":"file:src\rejuvenation-simple_factory.adb","fullyQualifiedN│             │
│ame":"src\rejuvenation-simple_factory.adb","type":"File"}             │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-nested.ads","subtype":"AdaSpecificationF│1            │
│ile","name":"file:src\rejuvenation-nested.ads","type":"File","fullyQua│             │
│lifiedName":"src\rejuvenation-nested.ads"}                            │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-file_utils.adb","subtype":"AdaBodyFile",│1            │
│"name":"file:src\rejuvenation-file_utils.adb","fullyQualifiedName":"sr│             │
│c\rejuvenation-file_utils.adb","type":"File"}                         │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-text_rewrites.ads","subtype":"AdaSpecifi│1            │
│cationFile","name":"file:src\rejuvenation-text_rewrites.ads","fullyQua│             │
│lifiedName":"src\rejuvenation-text_rewrites.ads","type":"File"}       │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-patterns.ads","subtype":"AdaSpecificatio│1            │
│nFile","name":"file:src\rejuvenation-patterns.ads","fullyQualifiedName│             │
│":"src\rejuvenation-patterns.ads","type":"File"}                      │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-pretty_print.ads","subtype":"AdaSpecific│1            │
│ationFile","name":"file:src\rejuvenation-pretty_print.ads","fullyQuali│             │
│fiedName":"src\rejuvenation-pretty_print.ads","type":"File"}          │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-string_utils.ads","subtype":"AdaSpecific│1            │
│ationFile","name":"file:src\rejuvenation-string_utils.ads","fullyQuali│             │
│fiedName":"src\rejuvenation-string_utils.ads","type":"File"}          │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-simple_factory.ads","subtype":"AdaSpecif│1            │
│icationFile","name":"file:src\rejuvenation-simple_factory.ads","fullyQ│             │
│ualifiedName":"src\rejuvenation-simple_factory.ads","type":"File"}    │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-text_rewrites.adb","subtype":"AdaBodyFil│1            │
│e","name":"file:src\rejuvenation-text_rewrites.adb","fullyQualifiedNam│             │
│e":"src\rejuvenation-text_rewrites.adb","type":"File"}                │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-nested.adb","subtype":"AdaBodyFile","nam│1            │
│e":"file:src\rejuvenation-nested.adb","type":"File","fullyQualifiedNam│             │
│e":"src\rejuvenation-nested.adb"}                                     │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-indentation.adb","subtype":"AdaBodyFile"│1            │
│,"name":"file:src\rejuvenation-indentation.adb","fullyQualifiedName":"│             │
│src\rejuvenation-indentation.adb","type":"File"}                      │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-node_locations.adb","subtype":"AdaBodyFi│1            │
│le","name":"file:src\rejuvenation-node_locations.adb","fullyQualifiedN│             │
│ame":"src\rejuvenation-node_locations.adb","type":"File"}             │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation-parameters.adb","subtype":"AdaBodyFile",│1            │
│"name":"file:src\rejuvenation-parameters.adb","fullyQualifiedName":"sr│             │
│c\rejuvenation-parameters.adb","type":"File"}                         │             │
├──────────────────────────────────────────────────────────────────────┼─────────────┤
│{"relativeName":"rejuvenation.ads","subtype":"AdaSpecificationFile","n│1            │
│ame":"file:src\rejuvenation.ads","fullyQualifiedName":"src\rejuvenatio│             │
│n.ads","type":"File"}                                                 │             │
└──────────────────────────────────────────────────────────────────────┴─────────────┘

Should the instances with only one reference (hence only include the "Rejuvenation" package, yet use none of its declarations)
remain part of the rejuvenation inheritance hierarchy?
Especially, file utils and string utils are NOT specific for rejuvenation!

@arjan.mooij What is your opinion?

context and semantic check don't work together

We want to

  • chain rewriters since reviewers should see only simple code. see
if c then f(true, y); else f (false, y); end if
-[original rewrite]->
f((if c then true else false), y);
-[simplification rewrite]->
f (c,y);
  • rewrite for a single reason, such that the goal of the review is clear to the reviewers and the changes are localized and related to that single reason. E.g. although the simplification can be applied at more places in the code, we only allow simplifications of already changed code.

The current solution that uses contexts is suitable for syntax rewrites but not for semantic checks.
We discovered this with the rewriter Rewriter_If_Assignment_Stmt.
It resulted in code that could be rewritten by Rewriter_Integer_Max_Greater_Than,
yet it could no longer determine what the type of the expressions were, since only a snippet of code is used.

A possible solution is to introduce markers, like for pretty printing.
Markers can be made with comments, but also with pragmas.
Note that this solution is slower, but since semantic checks can end up everywhere in the project, we can't prevent the reparsing of the whole, changed file(s)!

Add function to get type of placeholder

The type of a place holder might be needed to decide whether a rewrite is correct.

E.g. a and b rewritting to a and then b is only correct when a and b are booleans.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.